SPOJ QTREE
QTREE
- /*
- 题目大意:维护一棵树,允许修改边权以及查询链上最大值
- 题解:我们将边权转为点权,标记在深度较深的点上,树链剖分后用线段树处理即可
- */
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- const int N=20010;
- int top[N],nxt[N],v[N],g[N],d[N],son[N],f[N],size[N],st[N],en[N],dfn,ed;
- void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
- void init(){
- memset(g,dfn=ed=0,sizeof(g));
- memset(v,0,sizeof(v));
- memset(nxt,0,sizeof(nxt));
- memset(son,-1,sizeof(son));
- }
- void dfs(int x){
- size[x]=1;
- for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
- f[v[i]]=x,d[v[i]]=d[x]+1;
- dfs(v[i]),size[x]+=size[v[i]];
- if(size[v[i]]>size[son[x]])son[x]=v[i];
- }
- }
- void dfs2(int x,int y){
- st[x]=++dfn;top[x]=y;
- if(son[x])dfs2(son[x],y);
- for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
- en[x]=dfn;
- }
- struct Node{int l,r;int Max;}Tree[N*3];
- void build(int x,int l,int r){
- Tree[x].l=l;Tree[x].r=r;Tree[x].Max=0;
- if(l==r)return;int mid=(l+r)>>1;
- build(x<<1,l,mid);build((x<<1)|1,mid+1,r);
- }
- void up(int x){Tree[x].Max=max(Tree[x<<1].Max,Tree[(x<<1)|1].Max);}
- void update(int x,int k,int val){
- if(Tree[x].l==k&&Tree[x].r==k){Tree[x].Max=val;return;}
- int mid=(Tree[x].l+Tree[x].r)>>1;
- if(k<=mid)update(x<<1,k,val);
- else update((x<<1)|1,k,val);
- up(x);
- }
- int query(int x,int l,int r){
- if(Tree[x].l==l&&Tree[x].r==r)return Tree[x].Max;
- int mid=(Tree[x].l+Tree[x].r)>>1;
- if(r<=mid)return query(x<<1,l,r);
- else if(l>mid)return query((x<<1)|1,l,r);
- else return max(query(x<<1,l,mid),query((x<<1)|1,mid+1,r));
- }
- int find(int x,int y){
- int tmp=0;
- for(;top[x]!=top[y];x=f[top[x]]){
- if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
- tmp=max(tmp,query(1,st[top[x]],st[x]));
- }if(x==y)return tmp;
- if(d[x]>d[y]){int z=x;x=y;y=z;}
- return max(tmp,query(1,st[son[x]],st[y]));
- }int e[N][3];
- int main(int n,int T){
- scanf("%d",&T);
- while(T--){
- init(); scanf("%d",&n);
- for(int i=0;i<n-1;i++){
- scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
- add(e[i][0],e[i][1]);
- add(e[i][1],e[i][0]);
- }dfs(1);dfs2(1,1);
- build(1,1,dfn);
- for(int i=0;i<n-1;i++){
- if(d[e[i][0]]>d[e[i][1]])swap(e[i][0],e[i][1]);
- update(1,st[e[i][1]],e[i][2]);
- }char op[10]; int u,w;
- while(scanf("%s",op)==1){
- if(op[0]=='D')break;
- scanf("%d%d",&u,&w);
- if(op[0]=='Q')printf("%d\n",find(u,w));
- else update(1,st[e[u-1][1]],w);
- }
- }return 0;
- }
QTREE2
- /*
- 题目大意:给出一棵边权树,要求实现树链求和以及求链上第k个元素
- 题解:边权转点权后用LCT维护,注意求Qkth和sum时区别于点权树的讨论
- */
- #include <cstdio>
- #include <algorithm>
- #include <vector>
- #include <cstring>
- using namespace std;
- const int N=300010;
- namespace Link_Cut_Tree{
- vector<int> v[N],w[N];
- int f[N],son[N][2],tmp[N],size[N],val[N],sum[N];
- void init(){
- memset(val,0,sizeof(val));
- memset(sum,0,sizeof(sum));
- memset(f,0,sizeof(f));
- memset(son,0,sizeof(son));
- for(int i=1;i<N;i++)size[i]=1,v[i].clear(),w[i].clear();
- }
- bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
- void up(int x){
- sum[x]=val[x]+sum[son[x][0]]+sum[son[x][1]];
- size[x]=size[son[x][0]]+size[son[x][1]]+1;
- }
- void rotate(int x){
- int y=f[x],w=son[y][1]==x;
- son[y][w]=son[x][w^1];
- if(son[x][w^1])f[son[x][w^1]]=y;
- if(f[y]){
- int z=f[y];
- if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
- }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
- }
- void splay(int x){
- int s=1,i=x,y;tmp[1]=i;
- while(!isroot(i))tmp[++s]=i=f[i];
- while(!isroot(x)){
- y=f[x];
- if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
- rotate(x);
- }up(x);
- }
- void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
- // 求边权树的链和
- int ask(int x,int y){
- access(y),y=0;
- int ans=0;
- while(x){
- splay(x);
- if(!f[x])return sum[son[x][1]]+sum[y];
- son[x][1]=y; up(x);
- x=f[y=x];
- }
- }
- void dfs(int x,int fx){
- for(int i=0;i<v[x].size();i++){
- int y=v[x][i];
- if(y==fx)continue;
- f[y]=x;
- val[y]=w[x][i];
- dfs(y,x);
- }up(x);
- }
- int kth(int x,int k){
- while(size[son[x][0]]+1!=k){
- if(k<size[son[x][0]]+1)x=son[x][0];
- else{
- k-=size[son[x][0]]+1;
- x=son[x][1];
- }
- }return x;
- }
- // 求边权树u->v的第k个点
- int Qkth(int u,int v,int k){
- access(u),u=0;
- while(v){
- splay(v);
- if(!f[v]){
- if(size[son[v][1]]+1==k)return v;
- else if(size[son[v][1]]+1>k)return kth(son[v][1],size[son[v][1]]+1-k);
- else return kth(u,k-(size[son[v][1]]+1));
- }son[v][1]=u;
- up(v); v=f[u=v];
- }
- }
- }
- using namespace Link_Cut_Tree;
- int T,x,y,z,k,n;
- char op[10];
- int main(){
- scanf("%d",&T);
- while(T--){
- scanf("%d",&n);
- init();
- for(int i=1;i<n;i++){
- scanf("%d%d%d",&x,&y,&z);
- v[x].push_back(y);
- w[x].push_back(z);
- v[y].push_back(x);
- w[y].push_back(z);
- }dfs(1,0);
- while(scanf("%s",op)){
- if(op[1]=='O')break;
- if(op[0]=='D'){
- scanf("%d%d",&x,&y);
- printf("%d\n",ask(x,y));
- }
- else{
- scanf("%d%d%d",&x,&y,&k);
- printf("%d\n",Qkth(x,y,k));
- }
- }
- }return 0;
- }
QTREE3
- /*
- 题目大意:给出一棵一开始都是白点的树,要求维护操作:
- 1.将某个点的颜色取反(黑白互换)
- 2.查询1到x的路径上第一个黑色的点
- 题解:LCT维护子树中黑点的数量,对于颜色取反,则直接flap,
- 对于查询操作通过access(x)将1到x这条链取出,splay上查找即可
- 注意是从1到x,所以是makeroot(1),保证1节点的键值最小
- */
- #include <cstdio>
- #include <algorithm>
- #include <cstring>
- using namespace std;
- const int N=100010;
- namespace Link_Cut_Tree{
- int f[N],son[N][2],val[N],sum[N],tmp[N];bool rev[N];
- void init(){
- memset(f,0,sizeof(f));
- memset(son,0,sizeof(son));
- memset(val,0,sizeof(val));
- memset(rev,0,sizeof(rev));
- memset(sum,0,sizeof(sum));
- }
- bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
- void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
- void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
- void up(int x){sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];}
- void rotate(int x){
- int y=f[x],w=son[y][1]==x;
- son[y][w]=son[x][w^1];
- if(son[x][w^1])f[son[x][w^1]]=y;
- if(f[y]){
- int z=f[y];
- if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
- }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
- }
- void splay(int x){
- int s=1,i=x,y;tmp[1]=i;
- while(!isroot(i))tmp[++s]=i=f[i];
- while(s)pb(tmp[s--]);
- while(!isroot(x)){
- y=f[x];
- if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
- rotate(x);
- }up(x);
- }
- void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
- int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
- void makeroot(int x){access(x);splay(x);rev1(x);}
- void link(int x,int y){makeroot(x);f[x]=y;access(x);}
- int flip(int x){makeroot(x);val[x]^=1;up(x);}
- // 查询从1->x的第一个黑点
- int ask(int x){
- makeroot(1);
- access(x); splay(x); // splay只保证了x到根节点标记的下传
- if(!sum[x])return -1;
- while(x){
- pb(x); // 因为有makeroot操作,所以需要下传标记
- if(!sum[son[x][0]]&&val[x]==1)return x;
- else if(sum[son[x][0]])x=son[x][0];
- else x=son[x][1];
- }
- }
- }
- using namespace Link_Cut_Tree;
- int n,q,x,y;
- int main(){
- while(~scanf("%d%d",&n,&q)){
- init();
- for(int i=1;i<n;i++){
- scanf("%d%d",&x,&y);
- link(x,y);
- }
- while(q--){
- scanf("%d%d",&x,&y);
- if(x)printf("%d\n",ask(y));
- else flip(y);
- }
- }return 0;
- }
QTREE4
- /*
- 题目大意:给出一棵边权树,一开始所有点都是白点,
- 要求维护两种操作:
- 1.颜色取反(黑白互变)
- 2.查询树上最远的两个白点之间的距离
- 题解:我们维护重心树,对于每个重心维护分治层所有白点到其距离,
- 将其保存在对应方向子重心的优先队列中,
- 重心处另外维护一个队列保存该分治层每个子重心所产生的最大答案,即最大值加次大值,
- 那么每个重心处产生的最大答案的最值就是答案,
- 考虑修改问题,等价于在处理优先队列的删除问题,
- 对于每个需要删除操作的优先队列,我们额外创建一个优先队列将删除元素加入其中,
- 当两个队列top元素相同时同时删去即可。
- */
- #include <cstdio>
- #include <algorithm>
- #include <cstring>
- #include <queue>
- using namespace std;
- const int N=200010;
- const int INF=0x3f3f3f3f;
- int tot,g[N],nxt[N<<1],v[N<<1],w[N<<1];
- int TOT,G[N],NXT[N*20],V[N*20],W[N*20];
- void init(){
- memset(g,-1,sizeof(g));tot=0;
- memset(G,-1,sizeof(G));TOT=0;
- }
- void add_edge(int x,int y,int z){v[tot]=y,w[tot]=z,nxt[tot]=g[x],g[x]=tot++;}
- void ADD_EDGE(int x,int y,int z){V[TOT]=y,W[TOT]=z,NXT[TOT]=G[x],G[x]=TOT++;}
- int sum,root,size[N],dp[N],vis[N];
- void getroot(int x,int fx){
- size[x]=1; dp[x]=0;
- for(int i=g[x];~i;i=nxt[i]){
- if(!vis[v[i]]&&v[i]!=fx){
- getroot(v[i],x);
- size[x]+=size[v[i]];
- dp[x]=max(dp[x],size[v[i]]);
- }
- }dp[x]=max(dp[x],sum-size[x]);
- if(dp[x]<dp[root])root=x;
- }
- struct Que{
- priority_queue<int> Q,D;
- void clear(){
- while(!Q.empty())Q.pop();
- while(!D.empty())D.pop();
- }
- void add(int x){Q.push(x);}
- void del(int x){D.push(x);}
- int top(){
- for(;;){
- if(Q.empty())return -INF;
- else if(!D.empty()&&Q.top()==D.top())Q.pop(),D.pop();
- else return Q.top();
- }
- }
- int toptwo(){
- int x=top();
- del(x);
- int y=top();
- add(x);
- if(y==-INF)return x==-INF?x:0;
- return max(x+y,0);
- }
- }P[N],Q[N],ans;
- int dis[N],col[N];
- void getdis(int rt,int x,int fx){
- Q[rt].add(dis[x]);
- for(int i=g[x];~i;i=nxt[i]){
- if(v[i]==fx||vis[v[i]])continue;
- dis[v[i]]=dis[x]+w[i];
- getdis(rt,v[i],x);
- }
- }
- void getdeep(int rt,int x,int fx){
- ADD_EDGE(x,rt,dis[x]);
- for(int i=g[x];~i;i=nxt[i]){
- if(v[i]==fx||vis[v[i]])continue;
- dis[v[i]]=dis[x]+w[i];
- getdeep(rt,v[i],x);
- }
- }
- int belong[N];
- void build(int x,int fx,int from,int d){
- belong[x]=fx;
- dis[x]=0; getdeep(x,x,fx); P[x].add(0);
- if(fx){
- dis[from]=d;
- getdis(x,from,fx);
- P[fx].add(Q[x].top());
- }
- vis[x]=1;
- for(int i=g[x];~i;i=nxt[i])if(!vis[v[i]]){
- root=0; sum=size[v[i]];
- getroot(v[i],x);
- build(root,x,v[i],w[i]);
- }
- ans.add(P[x].toptwo());
- }
- void change(int rt){
- int a=P[rt].toptwo();
- if(col[rt])P[rt].add(0);
- else P[rt].del(0);
- int b=P[rt].toptwo();
- if(a!=b)ans.del(a),ans.add(b);
- int x=rt;
- for(int i=G[rt];~NXT[i];i=NXT[i]){
- int y=V[NXT[i]],len=W[NXT[i]];
- x=V[i];
- a=Q[x].top();
- if(col[rt])Q[x].add(len);
- else Q[x].del(len);
- b=Q[x].top();
- if(a!=b){
- int c=P[y].toptwo();
- P[y].del(a),P[y].add(b);
- int d=P[y].toptwo();
- if(c!=d)ans.del(c),ans.add(d);
- }
- }
- }
- int n,m,a,b,c,x;
- char op[10];
- int main(){
- scanf("%d",&n); init();
- for(int i=1;i<=n;i++)col[i]=1;
- for(int i=1;i<n;i++){
- scanf("%d%d%d",&a,&b,&c);
- add_edge(a,b,c);
- add_edge(b,a,c);
- }
- memset(vis,0,sizeof(vis));
- dp[root=0]=sum=n;
- getroot(1,0);
- build(root,0,0,0);
- scanf("%d",&m);
- int cnt=n;
- while(m--){
- scanf("%s",op);
- if(op[0]=='A'){
- if(cnt)printf("%d\n",ans.top());
- else puts("They have disappeared.");
- }else{
- scanf("%d",&x);
- col[x]^=1;
- if(col[x])cnt++;
- else cnt--;
- change(x);
- }
- }return 0;
- }
QTREE5
- /*
- 题目大意:给出一棵树,边权均为1,一开始所有点都是白点,
- 要求维护两种操作:
- 1.颜色取反(黑白互变)
- 2.查询树上某点距离最近的白点与其距离
- 题解:我们维护重心树,对于每个重心维护分治层所有白点到其距离,
- 将其保存在对应方向子重心的优先队列中,
- 重心处另外维护一个队列表示每个子重心的最小答案,
- 考虑修改问题,等价于在处理优先队列的删除问题,
- 对于每个需要删除操作的优先队列,我们额外创建一个优先队列将删除元素加入其中,
- 当两个队列top元素相同时同时删去即可。
- 对于查询操作,我们沿着重心链用经过每个重心的最优值更新答案
- */
- #include <cstdio>
- #include <algorithm>
- #include <cstring>
- #include <queue>
- using namespace std;
- const int N=200010;
- const int INF=0x3f3f3f3f;
- int tot,g[N],nxt[N<<1],v[N<<1],w[N<<1];
- int TOT,G[N],NXT[N*20],V[N*20],W[N*20];
- void init(){
- memset(g,-1,sizeof(g));tot=0;
- memset(G,-1,sizeof(G));TOT=0;
- }
- void add_edge(int x,int y,int z){v[tot]=y,w[tot]=z,nxt[tot]=g[x],g[x]=tot++;}
- void ADD_EDGE(int x,int y,int z){V[TOT]=y,W[TOT]=z,NXT[TOT]=G[x],G[x]=TOT++;}
- int sum,root,size[N],dp[N],vis[N];
- void getroot(int x,int fx){
- size[x]=1; dp[x]=0;
- for(int i=g[x];~i;i=nxt[i]){
- if(!vis[v[i]]&&v[i]!=fx){
- getroot(v[i],x);
- size[x]+=size[v[i]];
- dp[x]=max(dp[x],size[v[i]]);
- }
- }dp[x]=max(dp[x],sum-size[x]);
- if(dp[x]<dp[root])root=x;
- }
- struct Que{
- priority_queue<int,vector<int>,greater<int> > Q,D;
- void clear(){
- while(!Q.empty())Q.pop();
- while(!D.empty())D.pop();
- }
- void add(int x){Q.push(x);}
- void del(int x){D.push(x);}
- int top(){
- for(;;){
- if(Q.empty())return INF;
- else if(!D.empty()&&Q.top()==D.top())Q.pop(),D.pop();
- else return Q.top();
- }
- }
- }P[N],Q[N];
- int dis[N],col[N];
- void getdis(int rt,int x,int fx){
- for(int i=g[x];~i;i=nxt[i]){
- if(v[i]==fx||vis[v[i]])continue;
- dis[v[i]]=dis[x]+w[i];
- getdis(rt,v[i],x);
- }
- }
- void getdeep(int rt,int x,int fx){
- ADD_EDGE(x,rt,dis[x]);
- for(int i=g[x];~i;i=nxt[i]){
- if(v[i]==fx||vis[v[i]])continue;
- dis[v[i]]=dis[x]+w[i];
- getdeep(rt,v[i],x);
- }
- }
- int belong[N];
- void build(int x,int fx,int from,int d){
- belong[x]=fx;
- dis[x]=0; getdeep(x,x,fx);
- if(fx){
- dis[from]=d;
- getdis(x,from,fx);
- }
- vis[x]=1;
- for(int i=g[x];~i;i=nxt[i])if(!vis[v[i]]){
- root=0; sum=size[v[i]];
- getroot(v[i],x);
- build(root,x,v[i],w[i]);
- }
- }
- void change(int rt){
- if(col[rt])P[rt].add(0);
- else P[rt].del(0);
- int x=rt;
- for(int i=G[rt];~NXT[i];i=NXT[i]){
- int y=V[NXT[i]],len=W[NXT[i]];
- x=V[i];
- int a=Q[x].top();
- if(col[rt])Q[x].add(len);
- else Q[x].del(len);
- int b=Q[x].top();
- if(a!=b)P[y].del(a),P[y].add(b);
- }
- }
- int ask(int rt){
- int ans=INF;
- for(int i=G[rt];~i;i=NXT[i]){
- int x=V[i],len=W[i];
- int a=P[x].top();
- if(a+len<ans)ans=a+len;
- }
- return ans;
- }
- int n,m,a,b,c,x,op;
- int main(){
- scanf("%d",&n); init();
- for(int i=1;i<=n;i++)col[i]=0;
- for(int i=1;i<n;i++){
- scanf("%d%d",&a,&b);
- add_edge(a,b,1);
- add_edge(b,a,1);
- }
- memset(vis,0,sizeof(vis));
- dp[root=0]=sum=n;
- getroot(1,0);
- build(root,0,0,0);
- scanf("%d",&m);
- int cnt=0;
- while(m--){
- scanf("%d%d",&op,&x);
- if(op==1){
- if(cnt)printf("%d\n",ask(x));
- else puts("-1");
- }else{
- col[x]^=1;
- if(col[x])cnt++;
- else cnt--;
- change(x);
- }
- }return 0;
- }
QTREE6
- /*
- 题目大意:给出一棵树,一开始树上点均为黑色,要求维护操作
- 1.翻转某点的颜色(黑白互换),
- 2.查询某个点所在连通块(颜色相同则连通)大小
- 题解:我们分别维护黑点LCT和白点LCT,当一个点从黑变白时,
- 将其从黑点LCT中与父节点断开,然后在白点LCT中与父节点相连,
- 这样我们就保证了每个连通块在LCT中只有父节点是不同色的而其余一定是连通的。
- 考虑用LCT维护子树信息,根据在LCT上的连接情况,我们将点的儿子分为实儿子和虚儿子
- 实儿子是原本树结构上相连的点,实儿子的子树为实子树,虚儿子的子树为虚子树
- x的LCT子树的信息和等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己
- 在进行access操作时,我们会有更换一个点的x右儿子的操作,
- 这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,
- 把x的新的右儿子的LCT子树信息从x的虚子树信息中减去
- 同时在link x到y的时候,我们需要对y进行access再splay
- 这样就只会对y的虚子树信息和LCT子树信息产生影响,而不会影响到y的祖先节点
- */
- #include <cstdio>
- #include <algorithm>
- #include <set>
- const int N=100010;
- using namespace std;
- int n,m,i,k,x,y,c[N],fa[N],g[N],v[N<<1],nxt[N<<1],ed;
- struct LCT{
- int son[N][2],f[N],sum[N],s[N];
- bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
- void up(int x){sum[x]=1+sum[son[x][0]]+sum[son[x][1]]+s[x];}
- void rotate(int x){
- int y=f[x],w=son[y][1]==x;
- son[y][w]=son[x][w^1];
- if(son[x][w^1])f[son[x][w^1]]=y;
- if(f[y]){
- int z=f[y];
- if(son[z][0]==y)son[z][0]=x;
- if(son[z][1]==y)son[z][1]=x;
- }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
- }
- void splay(int x){
- while(!isroot(x)){
- int y=f[x];
- if(!isroot(y)){
- if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);
- else rotate(y);
- }rotate(x);
- }up(x);
- }
- void access(int x){
- for(int y=0;x;y=x,x=f[x]){
- splay(x);
- if(son[x][1])s[x]+=sum[son[x][1]];
- if(son[x][1]=y)s[x]-=sum[y];
- up(x);
- }
- }
- int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
- void link(int x){access(fa[x]);splay(fa[x]);splay(x);son[fa[x]][1]=x;up(f[x]=fa[x]);}
- void cut(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
- int ask(int x){splay(x=root(x));return sum[son[x][1]];}
- }T[2];
- void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
- void dfs(int x){
- for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x]){
- fa[v[i]]=T[c[v[i]]].f[v[i]]=x;
- dfs(v[i]);
- T[c[v[i]]].s[x]+=T[c[v[i]]].sum[v[i]];
- }T[0].up(x),T[1].up(x);
- }
- void read(int&a){
- char c;
- while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';
- while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
- }
- int main(){
- read(n);
- for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
- for(i=1;i<=n;i++)c[i]=0;
- fa[1]=T[c[1]].f[1]=n+1;dfs(1);
- T[c[1]].s[n+1]+=T[c[1]].sum[1];read(m);
- while(m--){
- read(k);read(x);
- if(!k)printf("%d\n",T[c[x]].ask(x));
- else T[c[x]].cut(x),T[c[x]^=1].link(x);
- }return 0;
- }
QTREE7
- /*
- 题目大意:给出一棵树,树上每个点为黑色或者白色,每个点有个点权,
- 我们认为树上颜色相同并通过边连接的块为连通块
- 要求维护操作:
- 0.查询x所在连通块中权值最大的点
- 1.翻转某点的颜色(黑白互换)
- 2.改变某点的权值
- 题解:我们分别维护黑点LCT和白点LCT,当一个点从黑变白时,
- 将其从黑点LCT中与父节点断开,然后在白点LCT中与父节点相连,
- 这样我们就保证了每个连通块在LCT中只有父节点是不同色的而其余一定是连通的。
- 考虑用LCT维护子树信息,根据在LCT上的连接情况,我们将点的儿子分为实儿子和虚儿子
- 实儿子是原本树结构上相连的点,实儿子的子树为实子树,虚儿子的子树为虚子树
- x的LCT子树的信息和等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己
- 在进行access操作时,我们会有更换一个点的x右儿子的操作,
- 这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,
- 把x的新的右儿子的LCT子树信息从x的虚子树信息中减去
- 同时在link x到y的时候,我们需要对y进行access再splay
- 这样就只会对y的虚子树信息和LCT子树信息产生影响,而不会影响到y的祖先节点
- 因为要维护的信息是极值,因此我们要用multiset来维护虚子树信息
- */
- #include <cstdio>
- #include <algorithm>
- #include <ctype.h>
- #include <set>
- const int N=100010;
- using namespace std;
- int n,m,k,x,y,c[N],fa[N],g[N],v[N<<1],nxt[N<<1],ed;
- struct LCT{
- int son[N][2],f[N],val[N],mx[N];
- multiset<int> s[N];
- bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
- void up(int x){
- mx[x]=val[x];
- if(s[x].size())mx[x]=max(mx[x],*s[x].rbegin());
- if(son[x][0])mx[x]=max(mx[x],mx[son[x][0]]);
- if(son[x][1])mx[x]=max(mx[x],mx[son[x][1]]);
- }
- void rotate(int x){
- int y=f[x],w=son[y][1]==x;
- son[y][w]=son[x][w^1];
- if(son[x][w^1])f[son[x][w^1]]=y;
- if(f[y]){
- int z=f[y];
- if(son[z][0]==y)son[z][0]=x;
- if(son[z][1]==y)son[z][1]=x;
- }f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
- }
- void splay(int x){
- while(!isroot(x)){
- int y=f[x];
- if(!isroot(y)){
- if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);
- else rotate(y);
- }rotate(x);
- }up(x);
- }
- void access(int x){
- for(int y=0;x;y=x,x=f[x]){
- splay(x);
- if(son[x][1])s[x].insert(mx[son[x][1]]);
- if(son[x][1]=y)s[x].erase(s[x].find(mx[y]));
- up(x);
- }
- }
- int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
- void link(int x){access(fa[x]);splay(fa[x]);splay(x);son[fa[x]][1]=x;up(f[x]=fa[x]);}
- void cut(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
- int ask(int x){
- int t=c[x]; splay(x=root(x));
- return t==c[x]?mx[x]:mx[son[x][1]];
- }
- void modify(int x,int v){access(x),splay(x),val[x]=v,up(x);}
- }T[2];
- void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
- void dfs(int x){
- for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x]){
- fa[v[i]]=T[c[v[i]]].f[v[i]]=x;
- dfs(v[i]);
- T[c[v[i]]].s[x].insert(T[c[v[i]]].mx[v[i]]);
- }T[0].up(x),T[1].up(x);
- }
- void read(int &x){
- char ch;
- for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
- int t;if(ch=='-')t=-1,ch=getchar();else t=1;
- for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
- x=x*t;
- }
- int main(){
- read(n);
- for(int i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
- for(int i=1;i<=n;i++)read(c[i]);
- for(int i=1;i<=n;i++)read(T[0].val[i]),T[1].val[i]=T[0].val[i];
- dfs(1); read(m);
- while(m--){
- read(k);read(x);
- if(k==0)printf("%d\n",T[c[x]].ask(x));
- else if(k==1)T[c[x]].cut(x),T[c[x]^=1].link(x);
- else if(k==2)read(y),T[0].modify(x,y),T[1].modify(x,y);
- }return 0;
- }
SPOJ QTREE的更多相关文章
- QTREE 树链剖分---模板 spoj QTREE
<树链剖分及其应用> 一文讲得非常清楚,我一早上就把他学会了并且A了这题的入门题. spoj QTREE 题目: 给出一棵树,有两种操作: 1.修改一条边的边权. 2.询问节点a到b的最大 ...
- SPOJ QTREE 系列解题报告
题目一 : SPOJ 375 Query On a Tree http://www.spoj.com/problems/QTREE/ 给一个树,求a,b路径上最大边权,或者修改a,b边权为t. #in ...
- SPOJ QTREE Query on a tree 树链剖分+线段树
题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...
- spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)
传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...
- SPOJ QTREE Query on a tree ——树链剖分 线段树
[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #incl ...
- 【学术篇】SPOJ QTREE 树链剖分
发现链剖这东西好久不写想一遍写对是有难度的.. 果然是熟能生巧吧.. WC的dalao们都回来了 然后就用WC的毒瘤题荼毒了我们一波, 本来想打个T1 44分暴力 然后好像是特判写挂了还是怎么的就只能 ...
- SPOJ QTree【树链剖分】
一 题目 QTREE 二 分析 第一道树链剖分的题,写的好艰难啊. 题意还是比较好理解的,就是在树上操作. 对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的. 对于查询,查询的时候,是 ...
- SPOJ QTREE Query on a tree
题意:给一颗n个点的树,有两种操作CHANGE i ti : 把第i条边的权变为tiQUERY a b : 问点a 到 点b 之间的边的最大权 思路:树剖处理边权.由于是边,所以只需要把边权处理到子节 ...
- SPOJ QTREE Query on a tree --树链剖分
题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. ...
随机推荐
- 2016.6.17——Remove Duplicates from Sorted Array
Remove Duplicates from Sorted Array 本题收获: 1.“删除”数组中元素 2.数组输出 题目: Given a sorted array, remove the du ...
- Dream------scala--类的属性和对象私有字段实战详解
Scala类的属性和对象私有字段实战详解 一.类的属性 scala类的属性跟java有比较大的不同,需要注意的是对象的私有(private)字段 1.私有字段:字段必须初始化(当然即使不是私有字段也要 ...
- Flask--wtforms快速使用和表单验证(附示例)
一.Form类 表单提供WTForms中最高级别的API.它们包含您的字段定义,委托验证,获取输入,聚合错误,并且通常用作将所有内容组合在一起的粘合剂. class wtforms.form.Form ...
- Django 内置模板标签和过滤器
一.内置模板标签 语法:{% %} autoescape : 是否转义,on或off作为参数,并确定自动转义是否在块内有效.该块以endautoescape结束 {% autoescape on % ...
- python网络编程--线程锁(互斥锁Mutex)
一:为什么需要线程锁 一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,会出现什么状况? 很简单,假设你有A,B两 ...
- Python 正则表达式提高
re模块的高级用法 search re.search(pattern, string[, flags]) 若string中包含pattern子串,则返回Match对象,否则返回None,注意,如果 ...
- 如何阻止点击scrollviewer里面的单位内容时,自动滚动
<Style TargetType="{x:Type ListBoxItem}"> <Setter Property="FocusVisualStyle ...
- JMeter接口&性能测试
JMeter接口测试 目前最新版本发展到5.0版本,需要Java7以上版本环境,下载解压目录后,进入\apache-jmeter-5.0\bin\,双击ApacheJMeter.jar文件启动JMem ...
- Unix IPC之Posix消息队列(2)
/* Query status and attributes of message queue MQDES. */ extern int mq_getattr (mqd_t __mqdes, stru ...
- Linux命令之cp命令
cp命令:用来将一个或多个源文件或者目录复制到指定的目的文件或目录.它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下.cp命令还支持同时复制多个文件,当一次复制多个文件时,目标 ...