BZOJ 3531 : [Sdoi2014]旅行
3531: [Sdoi2014]旅行
Description
S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,
S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
Input
输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。
Output
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
Sample Input
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
Sample Output
9
11
3
思路:
由于是在树上维护点与点之间路径的信息,考虑对树进行链剖再架线段树来解决。分析发现,我们只需要对每一种信仰开一颗线段树即可维护全部信息。当某城市更改信仰时,只需要把它从原来那颗树上归零,再在新树上加入,考虑动态开点即可。对于每种宗教维护区间合和区间最大值。代码如下
#include <cstring> #include <cstdio> #include <algorithm> #include <iostream> #include <cctype> #define im int mid = (l + r) >> 1 using namespace std; const int N = 200000; int son[N],siz[N],fa[N],top[N],dep[N]; int idx[N],cnt2; int to[N<<1],next[N<<1],val[N],head[N],b[N],cnt1; int n,m; int tr[N], ls[((N<<3)+(N<<1))<<1], rs[((N<<3)+(N<<1))<<1], sum[((N<<3)+(N<<1))<<1], maxn[((N<<3)+(N<<1))<<1]; class ReadIn { private: inline char nc() { static char buf[100000], *p1, *p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } public: inline int read() { int x=0;char ch=nc(); while(!isdigit(ch))ch=nc(); while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=nc();} return x; } inline char getc() { char ch=nc(); while(isspace(ch))ch=nc(); return ch; } }Rd; class SegmentTree { public : void change(int l,int r,int x,int y,int &p) { if(!p)p=++cnt2; if(l==r) { maxn[p]=sum[p]=y; return; } int mid = (l+r) >> 1; if(x<=mid) change(l,mid,x,y,ls[p]); else change(mid+1,r,x,y,rs[p]); sum[p]=sum[ls[p]]+sum[rs[p]]; maxn[p]=max(maxn[ls[p]],maxn[rs[p]]); } int qsum(int l,int r,int x,int y,int &p) { if(!p)return 0; if(x<=l&&r<=y) { return sum[p]; } int mid= (l+r) >> 1; int re = 0; if(x<=mid) re+=qsum(l,mid,x,y,ls[p]); if(y>mid) re+=qsum(mid+1,r,x,y,rs[p]); return re; } int qmax(int l,int r,int x,int y,int &p) { if(!p)return 0; if(x<=l&&r<=y) { return maxn[p]; } int mid= (l+r) >> 1; int re = 0; if(x<=mid) re=max(re,qmax(l,mid,x,y,ls[p])); if(y>mid) re=max(re,qmax(mid+1,r,x,y,rs[p])); return re; } }Tr; class TreeChainDissection { public : void dfs1(int p) { dep[p]=dep[fa[p]]+1; siz[p]=1; for (int i = head[p];i; i = next[i] ) { if(to[i] != fa[p]) { fa[to[i]]=p; dfs1(to[i]); siz[p]+=siz[to[i]]; if(siz[to[i]]>siz[son[p]]) son[p]=to[i]; } } } void dfs2(int p,int t) { idx[p]=++cnt2; top[p]=t; if(son[p]) dfs2(son[p],t); for(int i=head[p];i;i=next[i]) if(to[i]!=fa[p]&&to[i]!=son[p]) dfs2(to[i],to[i]); } int lcas(int x,int y) { int re = 0, root = b[x]; while(top[x] != top[y]) { if(dep[top[x]]>dep[top[y]]) swap(x,y); re+=Tr.qsum(1,n,idx[top[y]],idx[y],tr[root]); y=fa[top[y]]; } if(dep[x]<dep[y])swap(x,y); re+=Tr.qsum(1,n,idx[y],idx[x],tr[root]); return re; } int lcam(int x,int y) { int re=0, root = b[x]; while(top[x]!=top[y]) { if(dep[top[x]]>dep[top[y]]) swap(x,y); re = max(re,Tr.qmax(1,n,idx[top[y]],idx[y],tr[root])); y=fa[top[y]]; } if(dep[x]<dep[y])swap(x,y); re = max(re,Tr.qmax(1,n,idx[y],idx[x],tr[root])); return re; } }Tcd; class Pre { private : inline void add_edge(int a,int b) { to[++cnt1] = b; next[cnt1] = head[a]; head[a] = cnt1; to[++cnt1] = a; next[cnt1] = head[b]; head[b] = cnt1; } public : void init() { n=Rd.read(),m=Rd.read(); int i,x,y; for(i=1 ;i <=n; i++) val[i] = Rd.read(),b[i] = Rd.read(); for(i=1 ;i < n; i++) { x=Rd.read(),y=Rd.read(); add_edge(x,y); } Tcd.dfs1(1); Tcd.dfs2(1,1); for(i=1 ;i <=n; i++) { Tr.change(1,n,idx[i],val[i],tr[b[i]]); } } }Pr; void solve() { int i,x,y; char opt; for(i=1;i<=m;i++) { opt=Rd.getc(); opt=Rd.getc(); x = Rd.read(); y = Rd.read(); if(opt=='C') { Tr.change(1,n,idx[x],0,tr[b[x]]); b[x]=y; Tr.change(1,n,idx[x],val[x],tr[b[x]]); } else if(opt=='S'){ int ans=Tcd.lcas(x,y); printf("%d\n",ans); } else if(opt=='W') { Tr.change(1,n,idx[x],y,tr[b[x]]); val[x] = y; } else { int ans=Tcd.lcam(x,y); printf("%d\n", ans); } } } int main() { Pr.init(); solve(); }
欢迎来原博客看看 >原文地址<