BZOJ3531: [Sdoi2014]旅行

题解:  走路的时候 YY的一种写法啊  直接对于每个信仰动态开点然后维护最大值和区间和即可

#include <bits/stdc++.h>
#define ll long long
#define link(x) for(edge *j=h[x];j;j=j->next)
const int MAXN=1e5+10;
using namespace std;
int rt[MAXN],n,q;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
struct edge{int v;edge*next;}e[MAXN<<1],*h[MAXN<<1],*o=e;
void add(int x,int y){o->v=y;o->next=h[x];h[x]=o++;}
typedef struct node{
	int l,r,sum,maxx;
}node;
int a[MAXN],b[MAXN];
node d[MAXN*21];int cnt;
void up(int x){
	d[x].sum=d[d[x].l].sum+d[d[x].r].sum;
	d[x].maxx=max(d[d[x].l].maxx,d[d[x].r].maxx);
}
void update(int &x,int l,int r,int t,int vul){
	if(!x)x=++cnt;
	if(l==r){d[x].sum=d[x].maxx=vul;return ;}
	int mid=(l+r)>>1;
	if(t<=mid)update(d[x].l,l,mid,t,vul);
	else update(d[x].r,mid+1,r,t,vul);
	up(x);
}
pair<int,int>ans;
void querty(int x,int l,int r,int ql,int qr){
	if(!x)return ;
	if(ql<=l&&r<=qr){ans.first+=d[x].sum;ans.second=max(ans.second,d[x].maxx);return ;}
	int mid=(l+r)>>1;
	if(ql<=mid)querty(d[x].l,l,mid,ql,qr);
	if(qr>mid)querty(d[x].r,mid+1,r,ql,qr);
}
int num[MAXN],son[MAXN],dep[MAXN],fa[MAXN];
void dfs(int v,int pre,int deep){
	num[v]=1;dep[v]=deep+1;fa[v]=pre;
	link(v){
		if(j->v!=pre){
			dfs(j->v,v,deep+1);
			num[v]+=num[j->v];
			if(son[v]==-1||num[son[v]]<num[j->v])son[v]=j->v;
		}
	}
}
int p[MAXN],fp[MAXN],cnt1,tp[MAXN];
void dfs1(int v,int td){
	p[v]=++cnt1;fp[p[v]]=v;tp[v]=td;
	if(son[v]!=-1)dfs1(son[v],td);
	link(v)if(j->v!=son[v]&&j->v!=fa[v])dfs1(j->v,j->v);
}
int slove(int u,int v,int op,int c){
	int uu=tp[u];int vv=tp[v];
	ans.first=ans.second=0;
	while(uu!=vv){
		if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
		querty(rt[c],1,n,p[uu],p[u]);
		u=fa[uu];uu=tp[u];
	}
	if(dep[u]>dep[v])swap(u,v);
	querty(rt[c],1,n,p[u],p[v]);
	if(op==1)return ans.first;
	return ans.second;
}
int main(){
	int x,y;n=read();q=read();
	char str[11];
	for(int i=1;i<=n;i++)a[i]=read(),b[i]=read(),son[i]=-1;
	for(int i=1;i<n;i++)x=read(),y=read(),add(x,y),add(y,x);
	dfs(1,0,0);
	dfs1(1,1);
	for(int i=1;i<=n;i++)update(rt[b[i]],1,n,p[i],a[i]);
	for(int i=1;i<=q;i++){
		scanf("%s",str);x=read();y=read();
		if(str[1]=='C'){update(rt[b[x]],1,n,p[x],0);update(rt[y],1,n,p[x],a[x]);b[x]=y;}
		else if(str[1]=='W'){update(rt[b[x]],1,n,p[x],0);update(rt[b[x]],1,n,p[x],y);a[x]=y;}
		else if(str[1]=='S')printf("%d\n",slove(x,y,1,b[x]));
		else printf("%d\n",slove(x,y,2,b[x]));
	}
	return 0;
}

 

3531: [Sdoi2014]旅行

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 3105  Solved: 1385
[Submit][Status][Discuss]

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 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

Sample Output

8
9
11
3

HINT

N,Q < =10^5    , C < =10^5

 

 数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时

刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。

posted @ 2018-08-19 19:39  wang9897  阅读(141)  评论(0编辑  收藏  举报