HDU 4836 —— The Query on the Tree(線段樹+LCA)
下午百度之星複賽裡最簡單的一題,雖然我還是1個小時才AC的,呃,下午果斷被虐粗翔。
本題磨了1個小時才過,第1題還是很猥瑣地用了隨機數過的(真不知道怎麼做)。
回到這題來,其實也不知道大牛們怎麼做的,我只能用線段樹+LCA搞了。
首先考慮根不改變的情況,那麼我們可以將每個結點對映到線段樹上去,讓每個點對應的子樹的點都落在某個連續區間上;
具體是在dfs的時候,用id來表示當前已經對映到線段樹的編號,初始為0,進入某個結點X,令left[X]=right[X]=++id,然後繼續dfs,對於X每個子節點j,dfs完了順便更新right[X]=max(right[X], right[j]),這樣在所有子節點遍歷完的情況下,left[X]到right[X]就剛好是以X為根的子樹的區間。在紙上模擬下就明白了。
然後對於查詢和點更新就是個經典的線段樹問題了。
比較麻煩的是根被改變的情況,假設我們現在要查詢以X為根的子樹的和,分析下當前根是root時與原先的不同。如果root原來就是X的祖先了,那麼答案跟原來是一樣的,再往下想其實就是隻要root需要經過X原先某個祖先到達X的話,答案應該都一樣的,所以這個好辦。
而如果X剛好就是root,那麼答案就是整棵樹的和,也好處理。
剩下的就是原來X是root的祖先,我們假設X經過它的某個子節點Y到達root,那麼很明顯當前X的子樹和,應該是整棵樹的值減去原來Y對應的子樹的和。因為X-Y這條邊是root進行dfs到達X的最後一條邊,換句話說這條邊就把是不是X的子樹的點分隔開了。
分析到這裡問題就好辦了,對於查詢X,求出它們的最近公共祖先V,再進行判斷即可。
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; #define lson o<<1 #define rson (o<<1)|1 #define N 10001 #define pb push_back vector<int> V[N]; int t, ct, n; int left[N], right[N], val[N], v2[N]; int s[N<<2], l[N<<2], r[N<<2]; int id, root; bool f[N]; int depth[N], parent[16][N]; void dfs(int x){ left[x] = right[x] = ++id; v2[id] = val[x]; for(int i=0; i<V[x].size(); i++){ int j=V[x][i]; if(f[j]) continue; f[j]=1; depth[j] = depth[x]+1; parent[0][j] = x; dfs(j); right[x] = max(right[x], right[j]); } } void maintain(int o){ s[o] = s[lson]+s[rson]; } void build(int o, int ll, int rr){ l[o]=ll; r[o]=rr; s[o]=0; if(ll<rr){ int m = (ll+rr)>>1; build(lson, ll, m); build(rson, m+1, rr); maintain(o); } else{ s[o] = v2[ll]; } } void update(int o, int p, int v){ if(l[o]==p && r[o]==p){ s[o]=v; return; } int m = (l[o]+r[o])>>1; if(p<=m) update(lson, p, v); else update(rson, p, v); maintain(o); } void init_lca(){ for(int k=0; k<15; k++){ for(int v=1; v<=n; v++){ if(parent[k][v]<0) parent[k+1][v]=-1; else parent[k+1][v] = parent[k][parent[k][v]]; } } } int lca(int u, int v){ if(depth[u]>depth[v]){ swap(u,v); } for(int k=0; k<16; k++){ if((depth[v]-depth[u])>>k & 1){ v = parent[k][v]; } } if(u==v) return u; for(int k=15; k>=0; k--){ if(parent[k][u]!=parent[k][v]){ u=parent[k][u]; v=parent[k][v]; } } return parent[0][u]; } int query(int o, int ll, int rr){ if(l[o]==ll && r[o]==rr) return s[o]; int m = (l[o]+r[o])>>1; if(rr<=m) return query(lson, ll, rr); else if(ll>m) return query(rson, ll, rr); else return query(lson, ll, m)+query(rson, m+1, rr); } int query(int x){ if(x==root) return s[1]; int v = lca(root, x); if(v!=x){ return query(1, left[x], right[x]); } for(int i=0; i<V[x].size(); i++){ int j=V[x][i]; if(depth[j]<depth[x]) continue; v = lca(root, j); if(v==j){//找到前面所說的Y return s[1] - query(1, left[j], right[j]); } } return 0; } inline void in(int &x){ char c=getchar(); x=0; while(c<48 || c>57) c=getchar(); while(c>=48 && c<=57){ x = x*10+c-48; c = getchar(); } } int main(){ in(t); for(ct=1; ct<=t; ct++){ printf("Case #%d:\n", ct); in(n); for(int i=1; i<=n; i++) V[i].clear(); int x, y; for(int i=1; i<n; i++){ in(x); in(y); V[x].pb(y); V[y].pb(x); } for(int i=1; i<=n; i++){ in(val[i]); } memset(f,0,sizeof(f)); memset(parent,-1,sizeof(parent)); f[1]=1; id = 0; depth[1]=1; dfs(1); init_lca(); build(1, 1, n); int q; char op[10]; in(q); root=1; while(q--){ scanf("%s", op); in(x); if(op[0]=='Q'){ printf("%d\n", query(x)); } else if(op[0]=='C'){ in(y); update(1, left[x], y); } else{ root = x; } } } return 0; }
相關推薦
hdu-4836-The Query on the Tree(線段樹+LCA)
題目連結 思路:對於每次詢問,主要是看x和root的關係,求出root和xlca root=x ,ans為總的和 lca=x 那麼ans=總的和-(root到x這條鏈上父節點為x的那個點的子樹和) 否則,ans就是x的子樹和 求子樹和和修改直接線段樹維護。節點的編
HDU 4836 —— The Query on the Tree(線段樹+LCA)
下午百度之星複賽裡最簡單的一題,雖然我還是1個小時才AC的,呃,下午果斷被虐粗翔。 本題磨了1個小時才過,第1題還是很猥瑣地用了隨機數過的(真不知道怎麼做)。 回到這題來,其實也不知道大牛們怎麼做的,我只能用線段樹+LCA搞了。 首先考慮根不改變的情況,那麼我們可以將每個
SPOJ 375 Query on a tree(初學樹鏈剖分)
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions
HDU 4027 Can you answer these queries? (線段樹+暴力)
題意: 給出一段序列和兩種操作,第一種操作,將x,y區間的數均開平方,第二種操作,對x,y區間進行求和。 分析: 一開始還不敢用線段樹做,因為純線段樹下來根暴力列舉複雜度差不了多少,但由於開方,所以在很少次的迴圈裡就能達到1,所以就可以直接這麼做了。但題目沒有說名忍耐值的範圍,要是0太多
【HDU】4836 The Query on the Tree dfs+線段樹
題目分析:首先如果不換根的話,就可以用dfs求時間戳+樹狀陣列維護即可。 現在多了換根操作,我們該怎麼處理? 首先因為換根並不會改變樹的結構,所以我們依舊dfs出一棵樹來。 對於修改,我們改變該點在樹狀陣列上對應位置的值即可。 對於換根,我們直接將root置為要換的節
hdu 6191--Query on A Tree(持久化字典樹)
out trie scribe nodes include mathjax osi lan push_back 題目鏈接 Problem Description Monkey A lives on a tree, he always plays on this t
2017廣西邀請賽 Query on A Tree (可持續化字典樹)
題意 second for each follow n) nod pair content back Query on A Tree 時間限制: 8 Sec 內存限制: 512 MB提交: 15 解決: 3[提交][狀態][討論版] 題目描述 Monkey
hdu 5381 The sum of gcd(線段樹+gcd)
const HR LV oid pac vector AR statistic modify 題目鏈接:hdu 5381 The sum of gcd 將查詢離線
【HDU 6191】Query on A Tree 【可持久化字典樹】
algorithm stream %d ons turn class img cstring str 題目 給出一棵有n個結點的樹,樹根是1,每個結點給出一個value。然後給出q個詢問,每個詢問給出兩個整數u和x,你要在以u結點為根的子樹中找出一個結點v,使得val
SPOJ375——Query on a tree(樹鏈剖分模板詳解以及入門)
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfro
BZOJ_1803_Spoj1487 Query on a tree III_主席樹+dfs序
while out 主席樹 contains RR light oid contain space BZOJ_1803_Spoj1487 Query on a tree III_主席樹 Description You are given a node-labeled r
HDU-6035:Colorful Tree(虛樹+DP)
node different ase 得到 第一題 false all 直接 files 這裏有三道長得像的題: 一: HDU6036: There is a tree with nn nodes, eac
SPOJ COT Count on a tree(主席樹+倍增lca)
等於 lca amp oot namespace wap 1+n tor n) 思路:這個題其實就是樹上的第k小,主席樹的本質還是類似於前綴和一樣的結構,所以是完全相同的,所以我們在樹上也可以用同樣的方法,我們對於每一個節點進行建樹,然後和普通的樹上相同,ab之間的距離是等
Who Gets the Most Candies?(線段樹+模擬)
【題意】 NNN 個孩子順時針坐成一個圓圈(編號從 111 到 NNN ),每個孩子手中有一張卡片(上有一個非0整數)現在讓第K個孩子先淘汰,如果該孩子手中卡片上的數字A大於零,下一個出圈的是他左手邊第A個孩子,否則,下一個出圈的是他右手邊第A個孩子(當前孩子
Count the Colors(線段樹染色)
Count the Colors Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Description Painting some colored segme
POJ 題目2985 The k-th Largest Group(線段樹單點更新求第k大值,並查集)
The k-th Largest Group Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 7869 Accepted: 2534 Description Newman likes play
HDU 4027 Can you answer these queries?(線段樹區間開方)
sizeof sqrt .cn swap %d nes nts following clr Can you answer these queries? Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 6576
HDU 3340 Rain in ACStar(線段樹+幾何)
itl microsoft push php right not this string rain HDU 3340 Rain in ACStar pid=3340" target="_blank" style="">題目鏈接 題意:給定幾個多邊形(
POJ 題目3321 Apple Tree(線段樹)
nes num ons source 每一個 number autumn script ise Apple Tree Time Limit: 2000MS Memory Limit: 65536K Total Submission
HDU 5172 GTY's gay friends (線段樹)
ace tac 分享 log 沒有 http inf hdu algorithm 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5172 題意: 給你一個n個數的數組,m次詢問,詢問在[L, R] 這個區間裏面有沒有