LOJ2195 旅行
LOJ2195 旅行
题目描述
S 国有 N 个城市,编号从 1 到 N。城市间用 N-1 条双向道路连接,满足从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,S 国境内总共有 c 种不同的宗教。
S 国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S 国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在 S 国的历史上常会发生以下几种事件:
CC x c:城市 x 的居民全体改信了 c 教;
CW x w:城市 x 的评级调整为 w;
QS x y:一位旅行者从城市 x 出发,到城市 y,并记下了途中留宿过的城市的评级总和;
QM x y:一位旅行者从城市 x 出发,到城市 y,并记下了途中留宿过的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。
为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
输入格式
输入的第一行包含整数 N,Q 依次表示城市数和事件数。
接下来 N 行,第 i+1 行两个整数 Wi,Ci 依次表示记录开始之前,城市 i 的评级和信仰。
接下来 N-1 行每行两个整数 x,y 表示一条双向道路。
接下来 Q 行,每行一个操作,格式如上所述。
输出格式
对每个 QS 和 QM 事件,输出一行,表示旅行者记下的数字。
样例
样例输入
5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4
样例输出
8
9
1
3
数据范围与提示
对所有的数据,N,Q≤10^5, C≤10^5,对所有 QS 和 QM 事件,起点和终点城市的信仰相同;在任意时刻,城市的评级总是不大于 10^4 的正整数,且宗教值不大于 c。
_________________________________________________________________________________________
树链剖分,单点修改,求和。
但是由于只对对应的点(信奉相同的宗教)的点求和,而宗教的种类太多,每个线段树的点不能为10^5个点,所以要动态开点。
第一次写动态开点线段树,但过去用指针写过线段树,所以感觉不算难。
所谓动态开点,就是用不到的点先不要建点,只把对应的点建立,这样每次建一个点只需要建一条链(长logn)就可以了,不用的点先不用建。
其他的和普通线段树一样。
_________________________________________________________________________________________
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef int ll; 4 const ll maxn=1e5+10; 5 ll n,m; 6 struct edge 7 { 8 int u,v,nxt; 9 }e[maxn<<1]; 10 ll head[maxn],js; 11 void addage(ll u,ll v) 12 { 13 e[++js].u=u;e[js].v=v; 14 e[js].nxt=head[u];head[u]=js; 15 } 16 ll w[maxn],c[maxn]; 17 ll dep[maxn],fat[maxn],siz[maxn],son[maxn]; 18 void dfs(ll u,ll fa) 19 { 20 dep[u]=dep[fa]+1; 21 fat[u]=fa; 22 siz[u]=1; 23 for(ll i=head[u];i;i=e[i].nxt) 24 { 25 ll v=e[i].v; 26 if(v==fa)continue; 27 dfs(v,u); 28 siz[u]+=siz[v]; 29 if(!son[u] || siz[son[u]]<siz[v])son[u]=v; 30 } 31 } 32 ll p,pos[maxn],fos[maxn],top[maxn]; 33 void getpos(ll u,ll fa) 34 { 35 pos[u]=++p; 36 fos[p]=u; 37 top[u]=fa; 38 if(!son[u])return ; 39 getpos(son[u],fa); 40 for(ll i=head[u];i;i=e[i].nxt) 41 { 42 ll v=e[i].v; 43 if(v!=fat[u] && v!=son[u])getpos(v,v); 44 } 45 } 46 struct node 47 { 48 int lc,rc,sm,mx; 49 }t[2001000]; 50 int rt[maxn],cnt; 51 void update(ll cur) 52 { 53 t[cur].sm=t[t[cur].lc].sm+t[t[cur].rc].sm; 54 t[cur].mx=max(t[t[cur].lc].mx,t[t[cur].rc].mx); 55 } 56 void change(ll & cur,ll l,ll r,ll p,ll x) 57 { 58 if(!cur)cur=++cnt; 59 if(l==r) 60 { 61 t[cur].sm=t[cur].mx=x; 62 return ; 63 } 64 ll mid=(l+r)>>1; 65 if(p<=mid)change(t[cur].lc,l,mid,p,x); 66 else change(t[cur].rc,mid+1,r,p,x); 67 update(cur); 68 } 69 ll SUM,MAX; 70 void query(ll cur,ll l,ll r,ll ql,ll qr) 71 { 72 if(!cur)return ; 73 if(ql<=l && r<=qr) 74 { 75 SUM+=t[cur].sm; 76 MAX=max(MAX,t[cur].mx); 77 return ; 78 } 79 ll mid=(l+r)>>1; 80 if(ql<=mid)query(t[cur].lc,l,mid,ql,qr); 81 if(mid<qr)query(t[cur].rc,mid+1,r,ql,qr); 82 } 83 void ask(ll u,ll v) 84 { 85 SUM=0;MAX=0; 86 ll cl=c[u]; 87 ll tpu=top[u],tpv=top[v]; 88 while(tpu!=tpv) 89 { 90 if(dep[tpu]<dep[tpv]) 91 { 92 swap(u,v); 93 swap(tpu,tpv); 94 } 95 query(rt[cl],1,n,pos[tpu],pos[u]); 96 u=fat[tpu];tpu=top[u]; 97 } 98 if(dep[u]>dep[v])swap(u,v); 99 query(rt[cl],1,n,pos[u],pos[v]); 100 } 101 int main() 102 { 103 scanf("%d%d",&n,&m); 104 for(ll i=1;i<=n;++i)scanf("%d%d",w+i,c+i); 105 for(ll u,v,i=1;i<n;++i) 106 { 107 scanf("%d%d",&u,&v); 108 addage(u,v);addage(v,u); 109 } 110 dfs(1,0); 111 getpos(1,1); 112 for(ll i=1;i<=n;++i)change(rt[c[i]],1,n,pos[i],w[i]); 113 char s[4]; 114 ll u,v; 115 while(m--) 116 { 117 scanf("%s%d%d",s,&u,&v); 118 if(s[1]=='W') 119 { 120 w[u]=v; 121 change(rt[c[u]],1,n,pos[u],v); 122 } 123 else if(s[1]=='C') 124 { 125 change(rt[c[u]],1,n,pos[u],0); 126 c[u]=v; 127 change(rt[c[u]],1,n,pos[u],w[u]); 128 } 129 else if(s[1]=='S') 130 { 131 ask(u,v); 132 printf("%d\n",SUM); 133 } 134 else 135 { 136 ask(u,v); 137 printf("%d\n",MAX); 138 } 139 } 140 return 0; 141 }