bzoj 3531(動態加點線段樹,樹鏈剖分)

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);
  }
  }
}
}

發佈了149 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章