B20J_3231_[SDOI2014]旅行_树链剖分+线段树
题意:
S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教。
S国的居民常常旅行,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
以下几种操作:
? "CC x c":城市x的居民全体改信了c教;
? "CW x w":城市x的评级调整为w;
? "QS x y":一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
? "QM x y":一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级最大值。
分析:对每个宗教开一个线段树(动态开点)。CC操作时删除原来宗教所在线段树上该点的值,在新的宗教所在线段树中加入该点的值。
注意:
1.在查询时遇到一个空点要return。
2.修改时线段树上的值和本身的值都要修改
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N=100001; 6 int head[N],to[N<<1],nxt[N<<1],val[N],b[N],cnt; 7 int son[N],top[N],dep[N],fa[N],siz[N],idx[N],tot,cet; 8 int tree[N],lson[N*20],rson[N*20],d[N*20],m[N*20]; 9 void add(int u,int v) 10 { 11 to[++cnt]=v; 12 nxt[cnt]=head[u]; 13 head[u]=cnt; 14 } 15 int n,q; 16 char s[10]; 17 void dfs1(int x,int y) 18 { 19 fa[x]=y; 20 siz[x]=1; 21 dep[x]=dep[y]+1; 22 for(int i=head[x];i;i=nxt[i]) 23 { 24 if(to[i]!=y) 25 { 26 dfs1(to[i],x); 27 siz[x]+=siz[to[i]]; 28 if(siz[to[i]]>siz[son[x]]) 29 { 30 son[x]=to[i]; 31 } 32 } 33 } 34 } 35 void dfs2(int x,int t) 36 { 37 top[x]=t; 38 idx[x]=++tot; 39 if(son[x])dfs2(son[x],t); 40 for(int i=head[x];i;i=nxt[i]) 41 { 42 if(to[i]!=fa[x]&&to[i]!=son[x]) 43 { 44 dfs2(to[i],to[i]); 45 } 46 } 47 } 48 void up(int l,int r,int x,int y,int &p) 49 { 50 if(!p)p=++cet; 51 if(l==r) 52 { 53 d[p]=m[p]=y; 54 return ; 55 } 56 int mid=l+r>>1; 57 if(x<=mid)up(l,mid,x,y,lson[p]); 58 else up(mid+1,r,x,y,rson[p]); 59 d[p]=d[lson[p]]+d[rson[p]]; 60 m[p]=max(m[lson[p]],m[rson[p]]); 61 } 62 int qsum(int l,int r,int x,int y,int &p) 63 { 64 if(p==0)return 0; 65 if(x<=l&&r<=y) 66 { 67 return d[p]; 68 } 69 int mid=l+r>>1; 70 int re=0; 71 if(x<=mid) 72 { 73 re+=qsum(l,mid,x,y,lson[p]); 74 } 75 if(y>mid) 76 { 77 re+=qsum(mid+1,r,x,y,rson[p]); 78 } 79 return re; 80 } 81 int qmax(int l,int r,int x,int y,int &p) 82 { 83 if(p==0)return 0; 84 if(x<=l&&r<=y) 85 { 86 return m[p]; 87 } 88 int re=0; 89 int mid=l+r>>1; 90 if(x<=mid) 91 { 92 re=max(re,qmax(l,mid,x,y,lson[p])); 93 } 94 if(y>mid) 95 { 96 re=max(re,qmax(mid+1,r,x,y,rson[p])); 97 } 98 return re; 99 } 100 int main() 101 { 102 scanf("%d%d",&n,&q); 103 int x,y; 104 for(int i=1;i<=n;i++) 105 { 106 scanf("%d%d",&val[i],&b[i]); 107 } 108 for(int i=1;i<n;i++) 109 { 110 scanf("%d%d",&x,&y); 111 add(x,y); 112 add(y,x); 113 } 114 dfs1(1,0); 115 dfs2(1,1); 116 for(int i=1;i<=n;i++) 117 { 118 up(1,n,idx[i],val[i],tree[b[i]]); 119 } 120 for(int i=1;i<=q;i++) 121 { 122 scanf("%s%d%d",s,&x,&y); 123 if(s[1]==‘C‘) 124 { 125 up(1,n,idx[x],0,tree[b[x]]); 126 b[x]=y; 127 up(1,n,idx[x],val[x],tree[b[x]]); 128 } 129 else if(s[1]==‘S‘) 130 { 131 int re=0,rt=b[x]; 132 while(top[x]!=top[y]) 133 { 134 if(dep[top[x]]>dep[top[y]]) 135 swap(x,y); 136 re+=qsum(1,n,idx[top[y]],idx[y],tree[rt]); 137 y=fa[top[y]]; 138 } 139 if(dep[x]<dep[y])swap(x,y); 140 re+=qsum(1,n,idx[y],idx[x],tree[rt]); 141 printf("%d\n",re); 142 } 143 else if(s[1]==‘W‘) 144 { 145 up(1,n,idx[x],y,tree[b[x]]); 146 val[x]=y; 147 } 148 else 149 { 150 int re=0,rt=b[x]; 151 while(top[x]!=top[y]) 152 { 153 if(dep[top[x]]>dep[top[y]]) 154 swap(x,y); 155 re=max(re,qmax(1,n,idx[top[y]],idx[y],tree[rt])); 156 y=fa[top[y]]; 157 } 158 if(dep[x]<dep[y])swap(x,y); 159 re=max(re,qmax(1,n,idx[y],idx[x],tree[rt])); 160 printf("%d\n",re); 161 } 162 } 163 } 164 /*************************************************************** 165 Problem: 2456 166 User: 20170105 167 Language: C++ 168 Result: Accepted 169 Time:524 ms 170 Memory:42248 kb 171 ****************************************************************/