吐槽一波怎么今年的山东OI这么水……(装B
不难看出第一种操作就是LCT的access,那么每个点到根节点的颜色种数就是虚边数量+1,两点间颜色种数同理……
第三种操作可以用把每个虚边挂着的点的子树权值全部+1的方式来维护,那么直接LCT+区间修改区间求max的线段树维护即可,复杂度$O(nlog^2 n)$。
1 /************************************************************** 2 Problem: 4817 3 User: _Angel_ 4 Language: C++ 5 Result: Accepted 6 Time:5500 ms 7 Memory:21092 kb 8 ****************************************************************/ 9 #include<cstdio> 10 #include<cstring> 11 #include<algorithm> 12 #include<vector> 13 #define isroot(x) ((x)->p==null||((x)!=(x)->p->ch[0]&&(x)!=(x)->p->ch[1])) 14 #define dir(x) ((x)==(x)->p->ch[1]) 15 using namespace std; 16 const int maxn=100010; 17 struct node{node *ch[2],*p;}null[maxn]; 18 void dfs(int); 19 int LCA(int,int); 20 node *access(node*); 21 node *getroot(node*); 22 void splay(node*); 23 void rot(node*,int); 24 void modify(int,int,int); 25 int query(int,int,int); 26 int mx[maxn<<2]={0},lazy[maxn<<2]={0}; 27 vector<int>G[maxn]; 28 int f[maxn][20],d[maxn],dfn[maxn],finish[maxn],tim=0; 29 int n,m,lgn=0,s,t,k,x,y; 30 int main(){ 31 null->ch[0]=null->ch[1]=null->p=null; 32 scanf("%d%d",&n,&m); 33 for(int i=1;i<=n;i++)null[i].ch[0]=null[i].ch[1]=null[i].p=null; 34 for(int i=1;i<n;i++){ 35 scanf("%d%d",&x,&y); 36 G[x].push_back(y); 37 G[y].push_back(x); 38 } 39 dfs(1); 40 for(int j=1;j<=lgn;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1]; 41 while(m--){ 42 scanf("%d%d",&k,&x); 43 if(k==1)access(null+x); 44 else if(k==2){ 45 scanf("%d",&y); 46 s=t=dfn[x]; 47 int ans=query(1,n,1); 48 s=t=dfn[y]; 49 ans+=query(1,n,1); 50 s=t=dfn[LCA(x,y)]; 51 ans-=query(1,n,1)<<1; 52 printf("%d ",ans+1); 53 } 54 else if(k==3){ 55 s=dfn[x]; 56 t=finish[x]; 57 printf("%d ",query(1,n,1)+1); 58 } 59 } 60 return 0; 61 } 62 void dfs(int x){ 63 dfn[x]=++tim; 64 d[x]=d[f[x][0]]+1; 65 null[x].p=null+f[x][0]; 66 while((1<<lgn)<d[x])lgn++; 67 for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=f[x][0]){ 68 f[G[x][i]][0]=x; 69 dfs(G[x][i]); 70 } 71 finish[x]=tim; 72 if(f[x][0]){ 73 s=dfn[x]; 74 t=finish[x]; 75 k=1; 76 modify(1,n,1); 77 } 78 } 79 int LCA(int x,int y){ 80 if(d[x]!=d[y]){ 81 if(d[x]<d[y])swap(x,y); 82 for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i]; 83 } 84 if(x==y)return x; 85 for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){ 86 x=f[x][i]; 87 y=f[y][i]; 88 } 89 return f[x][0]; 90 } 91 node *access(node *x){ 92 node *y=null; 93 while(x!=null){ 94 splay(x); 95 if(x->ch[1]!=null){ 96 node *u=x->ch[1]; 97 x->ch[1]=null; 98 u=getroot(u); 99 s=dfn[u-null]; 100 t=finish[u-null]; 101 k=1; 102 modify(1,n,1); 103 } 104 if(y!=null){ 105 y=getroot(y); 106 s=dfn[y-null]; 107 t=finish[y-null]; 108 k=-1; 109 modify(1,n,1); 110 } 111 x->ch[1]=y; 112 y=x; 113 x=x->p; 114 } 115 return y; 116 } 117 node *getroot(node *x){ 118 splay(x); 119 while(x->ch[0]!=null)x=x->ch[0]; 120 splay(x); 121 return x; 122 } 123 void splay(node *x){ 124 while(!isroot(x)){ 125 if(isroot(x->p)){ 126 rot(x->p,dir(x)^1); 127 break; 128 } 129 if(dir(x)==dir(x->p))rot(x->p->p,dir(x->p)^1); 130 else rot(x->p,dir(x)^1); 131 rot(x->p,dir(x)^1); 132 } 133 } 134 inline void rot(node *x,int d){ 135 node *y=x->ch[d^1]; 136 if((x->ch[d^1]=y->ch[d])!=null)y->ch[d]->p=x; 137 y->p=x->p; 138 if(!isroot(x))x->p->ch[dir(x)]=y; 139 (y->ch[d]=x)->p=y; 140 } 141 void modify(int l,int r,int rt){ 142 if(s<=l&&t>=r){ 143 mx[rt]+=k; 144 lazy[rt]+=k; 145 return; 146 } 147 int mid=(l+r)>>1; 148 if(s<=mid)modify(l,mid,rt<<1); 149 if(t>mid)modify(mid+1,r,rt<<1|1); 150 mx[rt]=max(mx[rt<<1],mx[rt<<1|1])+lazy[rt]; 151 } 152 int query(int l,int r,int rt){ 153 if(s<=l&&t>=r)return mx[rt]; 154 int mid=(l+r)>>1,ans=0; 155 if(s<=mid)ans=max(ans,query(l,mid,rt<<1)); 156 if(t>mid)ans=max(ans,query(mid+1,r,rt<<1|1)); 157 return ans+lazy[rt]; 158 }
ps:如果没记错的话,这题应该是重组病毒那题的超级弱化版……