日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

1103: [POI2007]大都市meg(dfs序+线段树||树状数组)

發布時間:2023/12/15 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 1103: [POI2007]大都市meg(dfs序+线段树||树状数组) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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序+线段树||树状数组)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。