BZOJ3924: [Zjoi2015]幻想鄉戰略遊戲(動態點分治)
Description
傲嬌少女幽香正在玩一個非常有趣的戰略類遊戲,本來這個遊戲的地圖其實還不算太大,幽香還能管得過來,但是不知道為什麼現在的網遊廠商把遊戲的地圖越做越大,以至於幽香一眼根本看不過來,更別說和別人打仗了。 在打仗之前,幽香現在面臨一個非常基本的管理問題需要解決。 整個地圖是一個樹結構,一共有n塊空地,這些空地被n-1條帶權邊連線起來,使得每兩個點之間有一條唯一的路徑將它們連線起來。在遊戲中,幽香可能在空地上增加或者減少一些軍隊。同時,幽香可以在一個空地上放置一個補給站。 如果補給站在點u上,並且空地v上有dv個單位的軍隊,那麼幽香每天就要花費dv×dist(u,v)的金錢來補給這些軍隊。由於幽香需要補給所有的軍隊,因此幽香總共就要花費為Sigma(Dv*dist(u,v),其中1<=V<=N)的代價。其中dist(u,v)表示u個v在樹上的距離(唯一路徑的權和)。 因為遊戲的規定,幽香只能選擇一個空地作為補給站。在遊戲的過程中,幽香可能會在某些空地上製造一些軍隊,也可能會減少某些空地上的軍隊,進行了這樣的操作以後,出於經濟上的考慮,幽香往往可以移動他的補給站從而省一些錢。但是由於這個遊戲的地圖是在太大了,幽香無法輕易的進行最優的安排,你能幫幫她嗎? 你可以假定一開始所有空地上都沒有軍隊。
Input
第一行兩個數n和Q分別表示樹的點數和幽香操作的個數,其中點從1到n標號。 接下來n-1行,每行三個正整數a,b,c,表示a和b之間有一條邊權為c的邊。 接下來Q行,每行兩個數u,e,表示幽香在點u上放了e單位個軍隊 (如果e<0,就相當於是幽香在u上減少了|e|單位個軍隊,說白了就是du←du+e)。 資料保證任何時刻每個點上的軍隊數量都是非負的。 1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5Output
對於幽香的每個操作,輸出操作完成以後,每天的最小花費,也即如果幽香選擇最優的補給點進行補給時的花費。
Sample Input
10 51 2 1
2 3 1
2 4 1
1 5 1
2 6 1
2 7 1
5 8 1
7 9 1
1 10 1
3 1
2 1
8 1
3 1
4 1
Sample Output
01
4
5
6
解題思路:
相當於動態統計一棵樹的帶權重心。
怎麼搞呢?
序列上會不會。
不就是二分嗎,這東西會形成一個單峰函式。
證明我不會不過可以拿這個程式碼看一下。
#include<cstdio> #include<algorithm> typedef long long lnt; const int N=10; int a[]={0,101,2131,321,432,213,3124,5342,2323,5432,2323, 122,2511,321,432,2513,3132,5342,2323,5432,2323, 102,211,321,432,2133,3124,5342,2323,5432,2323, 12,2131,321,43124,52323,5432,2323, 102,231,21,43413224,5342,323,5432,3, 153,2131,213213,3124,5342,2323,543323, 102,21,321,43242,233,5432,2323, 502,2131,321,4,5342,2323,5432,2323 102,2131,321,53,2323,5432,2323, 12302,2131,3212,432,122342,2323,5432,2323, 103212,2131,321,432,21324,5312,28323,5432,23 1102,2131,321,432,213,3124,5342,2323,5432,3, 1023,2131,321,432,213,31124,5342,2323,543223, 103212,2131,321,432,213,3124,5342,2323,5432,3, 102,2131,321,432,5213,3124,5342,2323,5432,2323, 102,2131,321,432,213,3124,5342,2323,5432,2323,}; lnt fan(int pos) { lnt ans=0; for(int i=1;i<=N;i++) { ans+=1ll*std::abs(pos-i)*a[i]; } return ans; } int main() { for(int i=1;i<=N;i++) printf("%I64d ",fan(i)); return 0; }View Code
所以就是單峰了。
所以說就可以在樹上做同樣的試探動作。
如果一個點的答案更優秀那麼答案就在其子樹中。
可以知道一個點答案就是向父親走時加入容斥。
那個公式我就不推了QAQ。
維護三個答案,子到父代價,子樹代價,子樹全職和。
程式碼:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 const int N=100010; 6 struct pnt{ 7 int fa; 8 int hd; 9 int hf; 10 int dp; 11 int wgt; 12 int ind; 13 lnt dis; 14 lnt sum; 15 lnt diss; 16 lnt disf; 17 bool vis; 18 }p[N]; 19 struct ent{ 20 int twd; 21 int lst; 22 lnt vls; 23 }e[N<<2]; 24 int rt; 25 int n,m; 26 int cnt; 27 int dfn; 28 int root; 29 int size; 30 int maxsize; 31 int lg[N<<2]; 32 int eula[N<<2][21]; 33 void ade(int f,int t,lnt v) 34 { 35 cnt++; 36 e[cnt].twd=t; 37 e[cnt].vls=v; 38 e[cnt].lst=p[f].hd; 39 p[f].hd=cnt; 40 return ; 41 } 42 void adf(int f,int t,int lin) 43 { 44 cnt++; 45 e[cnt].twd=t; 46 e[cnt].vls=lin; 47 e[cnt].lst=p[f].hf; 48 p[f].hf=cnt; 49 return ; 50 } 51 void E_dfs(int x,int f) 52 { 53 eula[++dfn][0]=x; 54 p[x].ind=dfn; 55 p[x].dp=p[f].dp+1; 56 for(int i=p[x].hd;i;i=e[i].lst) 57 { 58 int to=e[i].twd; 59 if(to==f) 60 continue; 61 p[to].dis=p[x].dis+e[i].vls; 62 E_dfs(to,x); 63 eula[++dfn][0]=x; 64 } 65 return ; 66 } 67 int Emin(int x,int y) 68 { 69 return p[x].dp<p[y].dp?x:y; 70 } 71 int Lca(int x,int y) 72 { 73 x=p[x].ind; 74 y=p[y].ind; 75 if(x>y) 76 std::swap(x,y); 77 int l=lg[y-x+1]; 78 return Emin(eula[x][l],eula[y-(1<<l)+1][l]); 79 } 80 lnt Dis(int x,int y) 81 { 82 int z=Lca(x,y); 83 return p[x].dis+p[y].dis-2*p[z].dis; 84 } 85 void grc_dfs(int x,int f) 86 { 87 p[x].wgt=1; 88 int maxs=-1; 89 for(int i=p[x].hd;i;i=e[i].lst) 90 { 91 int to=e[i].twd; 92 if(to==f||p[to].vis) 93 continue; 94 grc_dfs(to,x); 95 p[x].wgt+=p[to].wgt; 96 if(p[to].wgt>maxs) 97 maxs=p[to].wgt; 98 } 99 maxs=std::max(maxs,size-p[x].wgt); 100 if(maxs<maxsize) 101 { 102 maxsize=maxs; 103 root=x; 104 } 105 return ; 106 } 107 void bin_dfs(int x,int f) 108 { 109 p[x].fa=f; 110 p[x].vis=true; 111 int tmp=size; 112 for(int i=p[x].hd;i;i=e[i].lst) 113 { 114 int to=e[i].twd; 115 if(p[to].vis) 116 continue; 117 root=0; 118 if(p[x].wgt<p[to].wgt) 119 size=tmp-p[x].wgt; 120 else 121 size=p[to].wgt; 122 maxsize=0x3f3f3f3f; 123 grc_dfs(to,to); 124 adf(x,root,to); 125 bin_dfs(root,x); 126 } 127 return ; 128 } 129 void update(int x,lnt y) 130 { 131 p[x].sum+=y; 132 for(int i=x;p[i].fa;i=p[i].fa) 133 { 134 p[p[i].fa].sum+=y; 135 lnt tmp=Dis(x,p[i].fa)*y; 136 p[i].disf+=tmp; 137 p[p[i].fa].diss+=tmp; 138 } 139 return ; 140 } 141 lnt assess(int x) 142 { 143 lnt ans=p[x].diss; 144 for(int i=x;p[i].fa;i=p[i].fa) 145 { 146 lnt tmp=Dis(x,p[i].fa); 147 ans+=tmp*(p[p[i].fa].sum-p[i].sum); 148 ans+=p[p[i].fa].diss-p[i].disf; 149 } 150 return ans; 151 } 152 lnt Query(void) 153 { 154 bool has=true; 155 lnt ans=assess(rt); 156 int lastpos=rt; 157 while(has) 158 { 159 has=false; 160 for(int i=p[lastpos].hf;i;i=e[i].lst) 161 { 162 int to=e[i].twd; 163 lnt tmp=assess(e[i].vls); 164 if(tmp<ans) 165 { 166 has=true; 167 ans=assess(to); 168 lastpos=to; 169 break; 170 } 171 } 172 } 173 return ans; 174 } 175 int main() 176 { 177 scanf("%d%d",&n,&m); 178 for(int i=1;i<n;i++) 179 { 180 int a,b; 181 lnt c; 182 scanf("%d%d%lld",&a,&b,&c); 183 ade(a,b,c); 184 ade(b,a,c); 185 } 186 E_dfs(1,1); 187 for(int i=2;i<=dfn;i++) 188 lg[i]=lg[i>>1]+1; 189 for(int i=1;i<=20;i++) 190 for(int j=1;j+(1<<i)-1<=dfn;j++) 191 eula[j][i]=Emin(eula[j][i-1],eula[j+(1<<(i-1))][i-1]); 192 root=0; 193 size=n; 194 maxsize=0x3f3f3f3f; 195 grc_dfs(1,1); 196 rt=root; 197 bin_dfs(root,0); 198 while(m--) 199 { 200 int x,y; 201 scanf("%d%d",&x,&y); 202 update(x,y); 203 printf("%lld\n",Query()); 204 } 205 return 0; 206 }