zoukankan      html  css  js  c++  java
  • bzoj3924 [Zjoi2015]幻想乡战略游戏

    动态点分治的题好恶心啊

    思路倒是比较简单,点分树上每个节点维护子树到他的权值和,到他父亲的权值和,以及点权和。

    发现查询的是带权重心,于是每次查到一个点,就在他原树的儿子中找一个比他优的,走到那边的点分树上的儿子,没有比他优的话答案就是他。

    一开始一直以为知道父亲的答案,儿子的答案可以$log$转移,后来发现不行,但是那样复杂度就变成了$O(nlg^3n)$,卡不过去,所以树上查询距离的话必须要欧拉序O(1)查询。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<vector>
      7 #define N 100500
      8 #define int long long
      9 using namespace std;
     10 int val[N];
     11 int e=1,head[N];
     12 struct edge{
     13     int v,w,next;
     14 }ed[N<<1];
     15 void add(int u,int v,int w){
     16     ed[e].v=v;ed[e].w=w;
     17     ed[e].next=head[u];
     18     head[u]=e++;
     19 }
     20 int a[2*N],L[N],R[N],cnt,minn[2*N][20],lg[2*N];
     21 void dfs(int x,int fa){
     22     a[++cnt]=val[x];L[x]=cnt;
     23     for(int i=head[x];i;i=ed[i].next){
     24         int v=ed[i].v;
     25         if(v==fa)continue;
     26         val[v]=val[x]+ed[i].w;
     27         dfs(v,x);a[++cnt]=val[x];
     28     }
     29     if(a[cnt]!=val[x])a[++cnt]=val[x];
     30     R[x]=cnt;
     31 }
     32 int dis(int x,int y){
     33     int l=R[x],r=L[y];
     34     if(l>r)swap(l,r);
     35     return val[x]+val[y]-2*min(minn[l][lg[r-l+1]],minn[r-(1<<lg[r-l+1])+1][lg[r-l+1]]);
     36 }
     37 int size[N],maxn[N];
     38 bool vis[N];
     39 int root,sum,rt,n,m,tot;
     40 int f[N];
     41 vector<pair<int,int> >son[N];
     42 void getroot(int x,int fa){
     43     size[x]=1;maxn[x]=0;
     44     for(int i=head[x];i;i=ed[i].next){
     45         int v=ed[i].v;
     46         if(v==fa||vis[v])continue;
     47         getroot(v,x);
     48         size[x]+=size[v];
     49         maxn[x]=max(maxn[x],size[v]);
     50     }
     51     maxn[x]=max(maxn[x],sum-size[x]);
     52     if(maxn[x]<maxn[root])root=x;
     53 }
     54 void init(int x){
     55     vis[x]=1;int all=sum;
     56     for(int i=head[x];i;i=ed[i].next){
     57         int v=ed[i].v;
     58         if(vis[v])continue;
     59         root=0;sum=size[v]<size[x]?size[v]:all-size[x];
     60         getroot(v,0);
     61         son[x].push_back(make_pair(v,root));
     62         f[root]=x;
     63         init(root);
     64     }
     65 }
     66 int sum1[N],sum2[N],num[N];
     67 void update(int x,int y){
     68     tot+=y;
     69     int now=x;
     70     while(now){
     71         num[now]+=y;
     72         sum1[now]+=y*dis(x,now);
     73         if(f[now])sum2[now]+=y*dis(x,f[now]);
     74         now=f[now];
     75     }
     76 }
     77 int query(int x){
     78     int ans=sum1[x],now=x;
     79     while(1){
     80         ans+=(sum1[f[now]]-sum2[now])+(num[f[now]]-num[now])*dis(x,f[now]);
     81         now=f[now];if(!f[now])break;
     82     }
     83     return ans;
     84 }
     85 int query(){
     86     int now=rt,last,val=sum1[rt];
     87     while(1){
     88         last=now;
     89         for(int i=0;i<son[now].size();i++){
     90             int v=son[now][i].first,nxt=son[now][i].second;
     91             int w=query(v);
     92             if(w<val){now=nxt;val=query(now);break;}
     93         }
     94         if(now==last)return val;
     95     }
     96 }
     97 void rmq(){
     98     for(int i=1,j=1,tim=0;(i>>1)<=cnt;i<<=1,tim++)
     99         while(j<=cnt&&j<(i<<1))lg[j++]=tim;
    100     for(int i=1;i<=cnt;i++)minn[i][0]=a[i];
    101     for(int i=1;(1<<i)<=cnt;i++)
    102         for(int j=1;j+(1<<i)-1<=cnt;j++)
    103             minn[j][i]=min(minn[j][i-1],minn[j+(1<<i-1)][i-1]);
    104 }
    105 signed main(){
    106     scanf("%lld%lld",&n,&m);
    107     for(int i=1,u,v,w;i<n;i++){
    108         scanf("%lld%lld%lld",&u,&v,&w);
    109         add(u,v,w);add(v,u,w);
    110     }
    111     dfs(1,1);rmq();
    112     root=0;maxn[0]=N;sum=n;
    113     getroot(1,0);
    114     rt=root;
    115     init(root);
    116     int x,y;
    117     while(m--){
    118         scanf("%lld%lld",&x,&y);
    119         update(x,y);
    120         printf("%lld
    ",query());
    121     }
    122     return 0;
    123 }
    View Code
  • 相关阅读:
    微擎使用函数获取用户微信信息
    xshell连接不上linux情况一
    destoon手机端分页
    kvm安装win2012
    kvm安装ubuntu
    KVM的磁盘管理相关
    ubuntu的iptables
    kvm安装win2003
    Centos-6.4 安装mysql-5.5.14
    CentOS 6.4安装bind-9.8.2最新版(DNS服务器)
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/8243994.html
Copyright © 2011-2022 走看看