Description 在經濟全球化浪潮的影響下,習慣于漫步在清晨的鄉間小路的郵遞員Blue Mary也開始騎著摩托車傳遞郵件了。 不過,她經常回憶起以前在鄉間漫步的情景。昔日,鄉下有依次編號為1…n的n個小村莊,某些村莊之間有一些雙 向的土路。從每個村莊都恰好有一條路徑到達村莊1(即比特堡)。并且,對于每個村莊,它到比特堡的路徑恰好 只經過編號比它的編號小的村莊。另外,對于所有道路而言,它們都不在除村莊以外的其他地點相遇。在這個未開 化的地方,從來沒有過高架橋和地下鐵道。隨著時間的推移,越來越多的土路被改造成了公路。至今,Blue Mary 還清晰地記得最后一條土路被改造為公路的情景。現在,這里已經沒有土路了——所有的路都成為了公路,而昔日 的村莊已經變成了一個大都市。 Blue Mary想起了在改造期間她送信的經歷。她從比特堡出發,需要去某個村莊, 并且在兩次送信經歷的間隔期間,有某些土路被改造成了公路.現在Blue Mary需要你的幫助:計算出每次送信她需 要走過的土路數目。(對于公路,她可以騎摩托車;而對于土路,她就只好推車了。)
Input 第一行是一個數n(1 < = n < = 2 50000).以下n-1行,每行兩個整數a,b(1 < = a以下一行包含一個整數m (1 < = m < = 2 50000),表示Blue Mary曾經在改造期間送過m次信。以下n+m-1行,每行有兩種格式的若干信息 ,表示按時間先后發生過的n+m-1次事件:若這行為 A a b(a若這行為 W a, 則表示Blue Mary曾經從比特堡送信到 村莊a。
Output 有m行,每行包含一個整數,表示對應的某次送信時經過的土路數目。
Sample Input 5
1 2
1 3
1 4
4 5
4
W 5
A 1 4
W 5
A 4 5
W 5
W 2
A 1 2
A 1 3
Sample Output 2
1
0
1 HINT 挺折磨人的一道題。。 首先得看懂題意,然后轉換題意。兩種操作:一種是求指定點的權值。另一種是更新一個區間。 將a-b的路徑改為公路可以視為將a-b的路徑的權值改為0,則題目轉為經一系列邊權的修改后詢問根節點與一個節點的距離。刷一遍DFS序,比如樣例中樹的dfs序為1223345541。將進入的權值賦為1,離開的權值賦為-1,起點的進出權值都為0(進出權值記錄在中間一行)。 得: 1 2 2 3 3 4 5 5 4 1 0 1 -1 1 -1 1 1 -1 -1 0 0 1 0 1 0 1 2 1 0 0 然后有什么用?我們可以發現起點到任意點N的距離都為N的進入點的前綴和(最下面一行)。 再試試修改,將1-4的權值改為0,只需將深度較深的點的進入權值改為0,離開的權值也改為0就好了。 1 2 2 3 3 4 5 5 4 1 0 1 -1 1 -1 0 1 -1 0 0 0 1 0 1 0 0 1 0 0 0 第二種操作直接修改深度大的點就好,這怎么也沒想到。直接線段樹或者樹狀數組修改就行。 ①:線段樹+dfs序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
using namespace std;const int maxx=250500;
int head[maxx],pre[maxx],s[maxx],t[maxx];
int dep[maxx],fa[maxx];
struct edge{int next;int to;
}e[maxx*2];
struct node{int l;int r;int v;int lazy;
}p[maxx*4];
int n,m,tot,sign;
/*-----------------事前準備----------------*/
void init()
{tot=sign=0;memset(head,-1,sizeof(head));memset(dep,-1,sizeof(dep));
}
void add(int u,int v)
{e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
/*--------------------dfs序-------------------*/
void dfs(int u,int f)
{dep[u]=dep[f]+1;s[u]=++sign;pre[sign]=u;fa[u]=f;for(int i=head[u];i!=-1;i=e[i].next){int to=e[i].to;if(to==f) continue;dfs(to,u);}t[u]=sign;
}
/*-------------------線段樹-------------------*/
void pushup(int cur)
{p[cur].v=p[2*cur].v+p[2*cur+1].v;
}
void pushdown(int cur)
{if(p[cur].lazy){p[2*cur].lazy+=p[cur].lazy;p[2*cur+1].lazy+=p[cur].lazy;p[2*cur].v+=p[cur].lazy;p[2*cur+1].v+=p[cur].lazy;p[cur].lazy=0;}
}
void build(int l,int r,int cur)
{p[cur].l=l;p[cur].r=r;p[cur].v=p[cur].lazy=0;if(l==r){p[cur].v=dep[pre[l]];return ;}int mid=(l+r)/2;build(l,mid,2*cur);build(mid+1,r,2*cur+1);pushup(cur);
}
void update(int l,int r,int cur,int v)
{int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].lazy+=v;p[cur].v+=v;return ;}pushdown(cur);int mid=(L+R)/2;if(r<=mid) update(l,r,2*cur,v);else if(l>mid) update(l,r,2*cur+1,v);else{update(l,mid,2*cur,v);update(mid+1,r,2*cur+1,v);}pushup(cur);
}
int query(int cur,int x)
{int L=p[cur].l;int R=p[cur].r;if(L==R){return p[cur].v;}pushdown(cur);int mid=(L+R)/2;if(x<=mid) return query(2*cur,x);else if(mid<x) return query(2*cur+1,x);
}
int main()
{init();scanf("%d",&n);int x,y;for(int i=1;i<n;i++){scanf("%d%d",&x,&y);add(x,y);add(y,x);}dfs(1,0);build(1,n,1);scanf("%d",&m);char xx[2];for(int i=1;i<=n+m-1;i++){scanf("%s",xx);if(xx[0]=='W'){scanf("%d",&x);printf("%d\n",query(1,s[x]));}else if(xx[0]=='A'){scanf("%d%d",&x,&y);x=max(x,y);update(s[x],t[x],1,-1);}}return 0;
}
②:樹狀數組+dfs序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#define ll long long
using namespace std;const int maxx=250500;
int head[maxx],pre[maxx],dep[maxx],s[maxx],t[maxx];
int sum[maxx];
struct edge{int to;int next;
}e[maxx*4];
int n,m,tot,sign;
int lowbit(int x){return x&-x;}
void init()
{tot=sign=0;memset(head,-1,sizeof(head));memset(dep,-1,sizeof(dep));memset(pre,0,sizeof(pre));
}
void add(int u,int v)
{e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
void dfs(int u,int f)
{dep[u]=dep[f]+1;s[u]=++sign;pre[sign]=u;for(int i=head[u];i!=-1;i=e[i].next){int to=e[i].to;if(to==f) continue;dfs(to,u);}t[u]=sign;
}
void update(int cur,int add)
{while(cur<=maxx*2){sum[cur]+=add;cur+=lowbit(cur);}
}
int query(int cur)
{int ans=0;while(cur>0){ans+=sum[cur];cur-=lowbit(cur);}return ans;
}
int main()
{init();scanf("%d",&n);int x,y;for(int i=1;i<n;i++){scanf("%d%d",&x,&y);add(x,y);add(y,x);}dfs(1,0);for(int i=2;i<=n;i++){update(s[i],1);update(t[i]+1,-1);}scanf("%d",&m);char xx[2];for(int i=1;i<=n+m-1;i++){scanf("%s",xx);if(xx[0]=='W'){scanf("%d",&x);printf("%d\n",query(s[x]));}else if(xx[0]=='A'){scanf("%d%d",&x,&y);update(max(s[x],s[y]),-1);update(min(t[x],t[y])+1,1);}}return 0;
}
線段樹再一次被虐。。 明天就回學校打多校了,希望是一個積極的暑假,別虛度了! 努力加油a啊,(o )/~
創作挑戰賽 新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔 為你收集整理的1103: [POI2007]大都市meg(dfs序+线段树||树状数组) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。