思路:显然的二分答案,不解释。
思路:有点不明显的状压dp(但看数据范围还是能猜出来的),状压颜色,然而还要前缀和预处理一下,并且每次找该状态的lowbit转移。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define inf 0x7fffffff
#define INF 0x3f3f3f3f
#define mcl(a,b) memset(a,b,sizeof(a))
#define Sz(a) sizeof(a)
#define N 100005
#define M 20
int n,K;
int A[N];
struct p20{
vector<int>E[N];
LL calc(int col){
LL ans=0;
int m=E[col].size();
if(m==1)return 0;
int x=m;
for(int i=0;iint p=E[col][i];
int s=n-x+1;
ans+=s-p;
x--;
}
return ans;
}
void solve(){
for(int i=1;i<=n;i++)scanf("%d",&A[i]),E[A[i]].push_back(i);
printf("%lld\n",min(calc(1),calc(2)));
}
}p20;
struct p100{
int cnt[M];
LL sum[1<1<int base[1<void Init(){
mcl(dp,INF);
REP(i,0,K-1)base[1<0][i]=dp[1<0;
}
void solve(){
REP(i,0,n-1){
scanf("%d",&A[i]);
A[i]--;
}
Init();
DREP(i,n-1,0){
REP(j,0,K-1)if(j!=A[i])last[A[i]][j]+=cnt[j];
cnt[A[i]]++;
}
REP(i,1,(1<1){
REP(j,0,K-1){
if((i&(1<continue;
int x=i&(-i);
sum[i][j]=sum[i-x][j]+last[j][base[x]];
}
}
REP(i,0,(1<1){
REP(j,0,K-1){
if(i&(1<continue;
dp[i|(1<1<cout<1<1]<int main(){
// freopen("robot.in","r",stdin);
// freopen("robot.out","w",stdout);
cin>>n>>K;
if(K==2)p20.solve();
else p100.solve();
return 0;
}
思路:与Paths神似,两条路径是否相交,即判断一条的lca是否被另一条路径经过,那么玄学的按照lca的deep从小到大排序,最后线段树维护一下即可求出答案。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define inf 0x7fffffff
#define INF 0x3f3f3f3f
#define mcl(a,b) memset(a,b,sizeof(a))
#define Sz(a) sizeof(a)
#define lson L,mid,p<<1
#define rson mid+1,R,p<<1|1
#define root 1,n,1
#define N 100005
#define M 1005
int n,m;
LL ans;
vector<int>E[N],vis[N];
int D[N],fa[N],son[N],top[N],sz[N];
int sgID[N],List[N],T;
int mark[M][M];
struct Node{
int from,to,lca;
bool operator<(const Node &a)const{
return D[lca]void dfs1(int x,int f){
D[x]=D[f]+1;
son[x]=0;
sz[x]=1;
fa[x]=f;
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==f)continue;
dfs1(y,x);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]])son[x]=y;
}
}
void dfs2(int x,int tp){
top[x]=tp;
sgID[x]=++T;
List[T]=x;
if(son[x])dfs2(son[x],tp);
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==fa[x] || y==son[x])continue;
dfs2(y,y);
}
}
int Lca(int a,int b){
while(top[a]!=top[b]){
if(D[top[a]]return D[a]struct p60{
void solve(){
dfs1(1,0);
dfs2(1,1);
REP(i,1,m){
int a=Q[i].from,b=Q[i].to,lca=Lca(a,b);
vis[lca].push_back(i);
while(a!=lca){
vis[a].push_back(i);
a=fa[a];
}
while(b!=lca){
vis[b].push_back(i);
b=fa[b];
}
}
LL ans=0;
REP(i,1,n){
if(vis[i].size()<2)continue;
REP(j,0,vis[i].size()-1){
REP(k,j+1,vis[i].size()-1){
int x=vis[i][j],y=vis[i][k];
if(x==y ||mark[x][y])continue;
mark[x][y]=mark[y][x]=1;
ans++;
}
}
}
cout<struct p100{
struct Tree{
struct node{
int L,R,sum;
}tree[N<<2];
void build(int L,int R,int p){
tree[p].L=L,tree[p].R=R;
tree[p].sum=0;
if(L==R)return;
int mid=(L+R)>>1;
build(lson),build(rson);
}
void update(int L,int R,int p){
if(tree[p].L==L && tree[p].R==R){
tree[p].sum++;
return;
}
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)update(L,R,p<<1);
else if(L>mid)update(L,R,p<<1|1);
else update(lson),update(rson);
}
void query(int x,int p){
ans+=tree[p].sum;
if(tree[p].L==tree[p].R)return;
int mid=(tree[p].L+tree[p].R)>>1;
if(x<=mid)query(x,p<<1);
else query(x,p<<1|1);
}
}Tree;
void change(int a,int b){
while(top[a]!=top[b]){
if(D[top[a]]1);
a=fa[top[a]];
}
if(D[a]>D[b])swap(a,b);
Tree.update(sgID[a],sgID[b],1);
}
void solve(){
dfs1(1,0);
dfs2(1,1);
REP(i,1,m)Q[i].lca=Lca(Q[i].from,Q[i].to);
sort(Q+1,Q+1+m);
Tree.build(root);
REP(i,1,m){
Tree.query(sgID[Q[i].lca],1);
change(Q[i].from,Q[i].to);
}
cout<int A[N<<1];
LL cnt[N],sum[N];
struct p_list{
bool check(){
REP(i,1,n)if(E[i].size()>2)return 0;
return 1;
}
void dfs(int x,int f){
D[x]=D[f]+1;
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==f)continue;
dfs(y,x);
}
}
void solve(){
int mm=0,s;
REP(i,1,n)if(E[i].size()==1){s=i;break;}
dfs(s,0);
REP(i,1,m){
int a=D[Q[i].from],b=D[Q[i].to];
if(a>b)swap(a,b);
A[++mm]=a;
A[++mm]=b+1;
cnt[a]++;
sum[b+1]++;
}
sort(A+1,A+mm+1);
int len=unique(A+1,A+mm+1)-A-1;
int now=0;
LL ans=0;
REP(i,1,len){
now-=sum[A[i]];
if(cnt[A[i]]>0)ans+=1LL*now*cnt[A[i]]+1LL*cnt[A[i]]*(cnt[A[i]]-1)/2;
now+=cnt[A[i]];
}
cout<int main(){
// freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
cin>>n>>m;
REP(i,1,n-1){
int a,b;
scanf("%d%d",&a,&b);
E[a].push_back(b);
E[b].push_back(a);
}
REP(i,1,m)scanf("%d%d",&Q[i].from,&Q[i].to);
if(n<=1000)p60.solve();
else if(p_list.check())p_list.solve();
else p100.solve();
return 0;
}
小结:今天考得不错,but第1题并不是敲了一遍就对了,还对拍了很久的小数据(该证明的还是要证明,该贪心的还是要贪心),并且要多考虑数据的一些下界和上界(很容易边界炸!!!);对dp还要再敏感一些,树上的题目该水的分一定要先水,再看有没有链的(话说这几次链的数据几乎都是错的…链还是多想想,这档分与正解相比不会太难)。