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
5 63 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
89
11
3
思路:
由于是在树上维护点与点之间路径的信息,考虑对树进行链剖再架线段树来解决。分析发现,我们只需要对每一种信仰开一颗线段树即可维护全部信息。当某城市更改信仰时,只需要把它从原来那颗树上归零,再在新树上加入,考虑动态开点即可。对于每种宗教维护区间合和区间最大值。代码如下
#include
#include
#include
#include
#include
#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[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] 欢迎来原博客看看 >原文地址<
转载于:https://www.cnblogs.com/Tobichi/p/9082489.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
