1. 程式人生 > >BZOJ3924: [Zjoi2015]幻想鄉戰略遊戲(動態點分治)

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^5
對於所有資料,這個樹上所有點的度數都不超過20 N,Q>=1

Output

 對於幽香的每個操作,輸出操作完成以後,每天的最小花費,也即如果幽香選擇最優的補給點進行補給時的花費。 

Sample Input

10 5
1 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

0
1
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 }