您的位置:首页 > 其它

bzoj 3531(动态加点线段树,树链剖分)

2016-07-18 09:39 253 查看

3531: [Sdoi2014]旅行

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1331  Solved: 629

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

Source

Round 1 Day 1

解题思路:对每个宗教开一个线段树。注意要动态开点,类似主席树。然后同样树链剖分。

#include<cstdio>

#include<iostream>

#include<algorithm>

#include<cstring>

using namespace std;

int n,q,len,cnt,ans,sug;

int to[210000],next[210000],h[210000];

int size[110000],deep[110000],fa[110000],son[110000],dui[110000],top[110000];

int ma[10100000],sum[10100000],w[210000],root[210000],c[210000];

int l[10100000],r[10100000];

char ch[3];

inline int read()

{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-')f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;

}

void insert(int x,int y)

 {

  ++len; to[len]=y; next[len]=h[x]; h[x]=len;

 }

void dfs(int now,int from,int dep)

 {

  size[now]=1; deep[now]=dep; fa[now]=from; son[now]=0;

  int u=h[now];

  while (u!=0)

  {

   if (to[u]!=from)

    {

    dfs(to[u],now,dep+1);

    size[now]+=size[to[u]]; if (size[to[u]]>size[son[now]]) son[now]=to[u];
}
 u=next[u];
}

 }

void dfs1(int now,int tg)

 {

  ++cnt;

  if (tg==-1) tg=now; top[now]=tg; dui[now]=cnt;

  if (son[now]==0) return;

  dfs1(son[now],tg);

  int u=h[now];

  while (u!=0)

  {

  if (to[u]!=fa[now] && to[u]!=son[now])

  {

  dfs1(to[u],-1);
  }
u=next[u];
 }

 }

void pushup(int now)

 {

  ma[now]=max(ma[l[now]],ma[r[now]]);

 }

void add(int &now,int lg,int rg,int zhi,int opp)

 {

  if (now==0) now=++sug; sum[now]+=zhi;

  if (lg==rg)

  {

  ma[now]+=zhi; return;
 }

  int mid=(lg+rg)/2;

  if (opp>mid) add(r[now],mid+1,rg,zhi,opp);else
 add(l[now],lg,mid,zhi,opp);
pushup(now); 

 }

void qusum(int now,int lg,int rg,int lo,int ro)

 {

  if (lo<=lg && rg<=ro) {ans+=sum[now];return;} 

  int mid=(lg+rg)/2;

  if (mid>=lo) qusum(l[now],lg,mid,lo,ro);

  if (mid+1<=ro) qusum(r[now],mid+1,rg,lo,ro);

 }

void qumax(int now,int lg,int rg,int lo,int ro)

 {

  if (lo<=lg && rg<=ro) {ans=max(ans,ma[now]);return;} 

  int mid=(lg+rg)/2;

  if (mid>=lo) qumax(l[now],lg,mid,lo,ro);

  if (mid+1<=ro) qumax(r[now],mid+1,rg,lo,ro);

 }

void getsum(int x,int y)

 {

  int opp=w[x];

  if (deep[x]<deep[y]) swap(x,y);

  ans=0;

  while (top[x]!=top[y])

  {

    if (deep[top[x]]>deep[top[y]]) qusum(root[opp],1,n,dui[top[x]],dui[x]),x=fa[top[x]];else

    qusum(root[opp],1,n,dui[top[y]],dui[y]),y=fa[top[y]];
}
qusum(root[opp],1,n,dui[y],dui[x]);
printf("%d\n",ans);

 }

void getmax(int x,int y)

 {

  int opp=w[x];

  if (deep[x]<deep[y]) swap(x,y);

    ans=0;

  while (top[x]!=top[y])

  {

    if (deep[top[x]]>deep[top[y]]) qumax(root[opp],1,n,dui[top[x]],dui[x]),x=fa[top[x]];else

    qumax(root[opp],1,n,dui[top[y]],dui[y]),y=fa[top[y]];
}
qumax(root[opp],1,n,dui[y],dui[x]);
printf("%d\n",ans);

 }

int main()

{
cnt=0;
n=read(); q=read();
for (int i=1;i<=n;++i)
{
c[i]=read(); w[i]=read();
}
for (int i=1;i<=n-1;++i)
{
int x,y; x=read(); y=read();
insert(x,y); insert(y,x);
}
sug=0;
dfs(1,0,0);
dfs1(1,-1);
for (int i=1;i<=n;++i)
{
add(root[w[i]],1,n,c[i],dui[i]);
}
for (int i=1;i<=q;++i)
{
scanf("%s",ch); int x,y; x=read(); y=read();
if (ch[0]=='C')
{
if (ch[1]=='C')
{
  add(root[w[x]],1,n,-c[x],dui[x]);
  w[x]=y;
  add(root[w[x]],1,n,c[x],dui[x]);

}else
 {
   add(root[w[x]],1,n,-c[x],dui[x]);
c[x]=y; 
add(root[w[x]],1,n,c[x],dui[x]); 
 }
 }else
  {
  if (ch[1]=='S')
   {
   
getsum(x,y);
   }else
    {
   
getmax(x,y);

  }
  }
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: