zoukankan      html  css  js  c++  java
  • 树上的点对

    【题意】

    给定一棵边带权的无根树,求树上距离不超过k的无序互异点对的个数。

    【解法】

    树分治练手题……

    三种分治,点分治,边分治,链分治,都可以。

    点分治应该也不难写,然而懒得写平衡树了,就用的相对好想好写的边分治。(因为感觉点分治需要用平衡树……)

    点分治是选重心当根节点,然后统计经过根节点的路径数。边分治则是直接找一个切断后能使两边的树尽量平衡的边,统计经过边的路径数。

    具体写的时候把两边的距离分别扔到两个vector里,然后二分即可。或者直接根据单调性线性扫描。

    统计路径的时候如果线性扫描的话,那么复杂度是O(nlogn),好像比点分治的O(nlog2n)快一些。然而由于常数限制,实际上还是很慢的。

    最坏情况下递归深度会达到O(n)(比如菊花形的树),所以要通过插入白点的方式改进最坏复杂度。通过在点到儿子的路径上插入白点来把每个点的儿子个数降到<=2,这样每个点的度数均不超过3,递归的最大深度为O(logn)。

    由于建成的树形似线段树,所以树的规模最多扩大一倍,只是常数问题。总复杂度还是O(nlogn)。

    第一次写树分治,写的比较丑……凑合看吧。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=50010;
      8 struct edge{
      9     int to,w,prev;
     10     bool vis;
     11 }e[maxn<<1];
     12 void predfs(int,int);//预处理,添白点
     13 void addedge(int,int,int);
     14 void solve(int);
     15 void dfs(int,int);//算size
     16 void dfs1(int,int,int&);//找用来分治的边
     17 void dfs2(int,int,int,vector<int>&);//算距离
     18 int n,k,last[maxn],len,size[maxn],siz,tmp,ans,du[maxn],x,y,z;
     19 bool white[maxn]={false};
     20 vector<int>a,b;
     21 vector<pair<int,int> >G[maxn];
     22 int main(){
     23 #define MINE
     24 #ifdef MINE
     25     freopen("poj1741_tree.in","r",stdin);
     26     freopen("poj1741_tree.out","w",stdout);
     27 #endif
     28     while(scanf("%d%d",&n,&k)==2&&n&&k){
     29         memset(last,-1,sizeof(last));
     30         memset(white,0,sizeof(white));
     31         memset(du,0,sizeof(du));
     32         for(int i=1;i<=20000;i++)G[i].clear();
     33         len=0;
     34         for(int i=1;i<n;i++){
     35             scanf("%d%d%d",&x,&y,&z);
     36             G[x].push_back(make_pair(y,z));
     37             G[y].push_back(make_pair(x,z));
     38         }
     39         ans=0;
     40         predfs(1,0);
     41         solve(1);
     42         printf("%d
    ",ans);
     43     }
     44 #ifndef MINE
     45     printf("
    --------------------DONE--------------------
    ");
     46     for(;;);
     47 #endif
     48     return 0;
     49 }
     50 void predfs(int x,int p){
     51     int cnt=G[x].size();
     52     for(int i=0;i<cnt;i++)if(G[x][i].first!=p)predfs(G[x][i].first,x);
     53     queue<pair<int,int> >q;
     54     for(int i=0;i<cnt;i++)if(G[x][i].first!=p)q.push(G[x][i]);
     55     cnt=q.size();
     56     while(cnt>2){
     57         pair<int,int>a=q.front();q.pop();
     58         pair<int,int>b=q.front();q.pop();
     59         int y=++n;
     60         white[y]=true;
     61         addedge(y,a.first,a.second);
     62         addedge(a.first,y,a.second);
     63         addedge(y,b.first,b.second);
     64         addedge(b.first,y,b.second);
     65         q.push(make_pair(y,0));
     66         cnt--;
     67     }
     68     while(!q.empty()){
     69         addedge(x,q.front().first,q.front().second);
     70         addedge(q.front().first,x,q.front().second);
     71         q.pop();
     72     }
     73 }
     74 void addedge(int x,int y,int z){
     75     e[len].to=y;
     76     e[len].w=z;
     77     e[len].prev=last[x];
     78     last[x]=len++;
     79 }
     80 void solve(int x){
     81     tmp=~(1<<31);
     82     int id=-1;
     83     dfs(x,0);
     84     siz=size[x];
     85     dfs1(x,0,id);
     86     if(id==-1)return;
     87     e[id].vis=e[id^1].vis=true;
     88     solve(e[id].to);
     89     solve(e[id^1].to);
     90     a.clear();
     91     b.clear();
     92     dfs2(e[id].to,0,0,a);
     93     dfs2(e[id^1].to,0,0,b);
     94     sort(a.begin(),a.end());
     95     sort(b.begin(),b.end());
     96     int cnta=a.size(),cntb=b.size();
     97     for(int i=0,j=cntb-1;i<cnta;i++){
     98         while(~j&&k-a[i]-e[id].w<b[j])j--;
     99         ans+=j+1;
    100     }
    101     e[id].vis=e[id^1].vis=false;
    102 }
    103 void dfs(int x,int p){
    104     size[x]=1;
    105     for(int i=last[x];i!=-1;i=e[i].prev)if(e[i].to!=p&&!e[i].vis){
    106         dfs(e[i].to,x);
    107         size[x]+=size[e[i].to];
    108     }
    109 }
    110 void dfs1(int x,int p,int &id){
    111     for(int i=last[x];i!=-1;i=e[i].prev)if(e[i].to!=p&&!e[i].vis){
    112         if(abs(size[e[i].to]-(siz-size[e[i].to]))<tmp){
    113             id=i;
    114             tmp=abs(size[e[i].to]-(siz-size[e[i].to]));
    115         }
    116         dfs1(e[i].to,x,id);
    117     }
    118 }
    119 void dfs2(int x,int p,int d,vector<int>&a){
    120     if(!white[x])a.push_back(d);
    121     for(int i=last[x];i!=-1;i=e[i].prev)if(e[i].to!=p&&!e[i].vis)dfs2(e[i].to,x,d+e[i].w,a);
    122 }
    View Code

    【后记】

    第一道树分治,就这样献给边分治了……

    看好多神犇用的都是点分治,感觉自己真奇葩……

     

    尽头和开端,总有一个在等你。

  • 相关阅读:
    修复文件系统
    遗忘root密码,对密码进行重置
    grub引导程序破坏修复下
    模拟Grub引导故障上(配置文件损坏)
    模拟MBR故障修复
    RAID5 制作 (一个硬盘制作)
    RAID10 (硬盘制作)
    du,df区别
    07_软件的安装
    06_find-查找文件
  • 原文地址:https://www.cnblogs.com/hzoier/p/6034699.html
Copyright © 2011-2022 走看看