bzoj3784 树上的路径

Description
给定一个N个结点的树,结点用正整数1..N编号。每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路边上经过边的权值。其中要求a<b.将这n*(n-1)/2个距离从大到小排序,输出前M个距离值。

Input
第一行两个正整数N,M
下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000)。表示结点a到结点b有一条权值为c的边。

Output
共M行,如题所述.

Sample Input
5 10
1 2 1
1 3 2
2 4 3
2 5 4

Sample Output
7
7
6
5
4
4
3
3
2
1

Sample Input
4 6
1 2 1
1 3 2
1 4 4

Sample Output
6
5
4
3
2
1

HINT
N<=50000,M<=Min(300000,n*(n-1)/2)

以下仅为解题记录(并非题解)

首先点分治,对每个节点搞出它所管辖的连通块中各个点到它的距离(包括自身,距离就是0),放进一个vector。

处理出每个点的vector后,分别对各个vector中的元素排序,然后用堆取前k大答案。

然后就会发现,这样是有问题的,还不是一点点的问题,这样不能把同子树的分离开。。。。

(我到底在想些什么才能连这一点都想不到的啊。。。。。)

然而这个好办,只要在搞出每个点管辖区域的各个点到它的距离时,顺便多记录一个值——每一个距离对应的子树编号。

然后我就非常naive地在最后输出答案的时候,如果堆中弹出的是不合法的(有相同子树编号的),就跳过

  1 #pragma GCC optimize("Ofast")
  2 #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
  3 #pragma GCC diagnostic error "-fwhole-program"
  4 #pragma GCC diagnostic error "-fcse-skip-blocks"
  5 #pragma GCC diagnostic error "-funsafe-loop-optimizations"
  6 #pragma GCC diagnostic error "-std=c++14"
  7 #include<cstdio>
  8 #include<algorithm>
  9 #include<vector>
 10 #include<queue>
 11 #include<map>
 12 using namespace std;
 13 typedef long long LL;
 14 typedef pair<LL,int> P;
 15 struct E
 16 {
 17     int to,nxt,d;
 18 }e[400100];
 19 int f1[200100],n,k,ne;
 20 vector<P> xx[200100];
 21 //表示i点管辖的连通块内各点到自身的距离(second表示子树编号)
 22 vector<int> nowed[200100];
 23 //表示xx[i]中取,左端点取j时,当前取右端点的位置
 24 int fx[200100],root,sz[200100],sum,nowsec;
 25 LL dep[200010];
 26 bool vis[200100];
 27 struct Info
 28 {
 29     LL ans;int nn,l;
 30     Info(LL a=0,int b=0,int c=0)
 31         :ans(a),nn(b),l(c)
 32     {}
 33     friend bool operator<(const Info &a,const Info &b)
 34     {
 35         return a.ans<b.ans;
 36     }
 37 };
 38 priority_queue<Info> q;
 39 void getroot(int u,int fa)
 40 {
 41     fx[u]=0;sz[u]=1;
 42     for(int k=f1[u];k;k=e[k].nxt)
 43         if(!vis[e[k].to]&&e[k].to!=fa)
 44         {
 45             getroot(e[k].to,u);
 46             fx[u]=max(fx[u],sz[e[k].to]);
 47             sz[u]+=sz[e[k].to];
 48         }
 49     fx[u]=max(fx[u],sum-sz[u]);
 50     if(fx[u]<fx[root])   root=u;
 51 }
 52 void getsz(int u,int fa)
 53 {
 54     sz[u]=1;
 55     for(int k=f1[u];k;k=e[k].nxt)
 56         if(!vis[e[k].to]&&e[k].to!=fa)
 57         {
 58             getsz(e[k].to,u);
 59             sz[u]+=sz[e[k].to];
 60         }
 61 }
 62 void getdeep(int u,int fa)
 63 {
 64     xx[root].push_back(P(dep[u],nowsec));
 65     for(int k=f1[u];k;k=e[k].nxt)
 66         if(!vis[e[k].to]&&e[k].to!=fa)
 67         {
 68             dep[e[k].to]=dep[u]+e[k].d;
 69             getdeep(e[k].to,u);
 70         }
 71 }
 72 void gdep(LL u)
 73 {
 74     int now=0;xx[root].push_back(P(dep[u],0));
 75     for(int k=f1[u];k;k=e[k].nxt)
 76         if(!vis[e[k].to])
 77         {
 78             dep[e[k].to]=dep[u]+e[k].d;
 79             nowsec=++now;
 80             getdeep(e[k].to,u);
 81         }
 82 }
 83 void solve(int u)
 84 {
 85     vis[u]=1;
 86     for(int k=f1[u];k;k=e[k].nxt)
 87         if(!vis[e[k].to])
 88         {
 89             getsz(e[k].to,0);sum=sz[e[k].to];
 90             root=0;getroot(e[k].to,0);
 91             dep[root]=0;gdep(root);
 92             solve(root);
 93         }
 94 }
 95 int main()
 96 {
 97     int i,j,u,v,l,ed;Info t;
 98     fx[0]=0x3f3f3f3f;
 99     scanf("%d%d",&n,&k);
100     for(i=1;i<n;i++)
101     {
102         scanf("%d%d%d",&u,&v,&l);
103         e[++ne].to=v;e[ne].nxt=f1[u];e[ne].d=l;f1[u]=ne;
104         e[++ne].to=u;e[ne].nxt=f1[v];e[ne].d=l;f1[v]=ne;
105     }
106     sum=n;getroot(1,0);
107     dep[root]=0;gdep(root);
108     solve(root);
109     for(i=1;i<=n;i++)    sort(xx[i].begin(),xx[i].end());
110     for(i=1;i<=n;i++)
111     {
112         ed=xx[i].size()-1;
113         nowed[i].reserve(ed+1);
114         for(j=0;j<ed;j++)
115         {
116             nowed[i][j]=ed;
117             q.push(Info(xx[i][ed].first+xx[i][j].first,i,j));
118         }
119     }
120     for(i=1;i<=k;)
121     {
122         t=q.top();q.pop();
123         if(xx[t.nn][t.l].second!=xx[t.nn][nowed[t.nn][t.l]].second)
124         {
125             ++i;
126             printf("%lld\n",t.ans);
127         }
128         --nowed[t.nn][t.l];
129         if(nowed[t.nn][t.l]>t.l)
130         {
131             q.push(Info(xx[t.nn][nowed[t.nn][t.l]].first+xx[t.nn][t.l].first,t.nn,t.l));
132         }
133     }
134     return 0;
135 }
View Code

想想都知道不对啊。。。复杂度肯定不对的啊。。。。。毫不意外地T掉了,卡常也没用,不知道是不是特殊设计的数据

然后去看了题解,有了新思路:对于任一个点搞出的vector,都不进行排序,这样的话其内部就是按子树编号排序的。

如果以其中某一个点作为路径的一个端点,那么另外一个点就可以从这个vector里面除了子树编号与其相同的那一段以外的几段中选。

考虑与超级钢琴类似的做法,那么只需要一个rmq就可以解决了

我先用st表写rmq,然后无限MLE。。。。(我做的是n<=200000)其中还涉及了一些关于vector的奇妙操作,但是并没有拯救我

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<vector>
  4 #include<queue>
  5 #include<map>
  6 using namespace std;
  7 typedef long long LL;
  8 typedef pair<LL,int> P;
  9 struct E
 10 {
 11     int to,nxt,d;
 12 }e[400100];
 13 int f1[200100],n,k,ne;
 14 vector<P> xx[200100];
 15 //表示i点管辖的连通块内各点到自身的距离(second表示子树编号)
 16 vector<int> rmq[200100][19];
 17 vector<int> st,ed;
 18 //表示i点管辖的连通块内各个子树编号对应的xx内始、终位置
 19 int fx[200100],root,sz[200100],sum,nowsec;
 20 int lft[30],log2x[200100];
 21 LL dep[200010];
 22 bool vis[200100];
 23 struct Info
 24 {
 25     LL ans;int nn,l,r,anspos,pos;
 26     Info(){}
 27     Info(LL a,int b,int c,int d,int e,int f)
 28         :ans(a),nn(b),l(c),r(d),anspos(e),pos(f)
 29     {}
 30     friend bool operator<(const Info &a,const Info &b)
 31     {
 32         return a.ans<b.ans;
 33     }
 34 };
 35 priority_queue<Info> q;
 36 void getroot(int u,int fa)
 37 {
 38     fx[u]=0;sz[u]=1;
 39     for(int k=f1[u];k;k=e[k].nxt)
 40         if(!vis[e[k].to]&&e[k].to!=fa)
 41         {
 42             getroot(e[k].to,u);
 43             fx[u]=max(fx[u],sz[e[k].to]);
 44             sz[u]+=sz[e[k].to];
 45         }
 46     fx[u]=max(fx[u],sum-sz[u]);
 47     if(fx[u]<fx[root])   root=u;
 48 }
 49 void getsz(int u,int fa)
 50 {
 51     sz[u]=1;
 52     for(int k=f1[u];k;k=e[k].nxt)
 53         if(!vis[e[k].to]&&e[k].to!=fa)
 54         {
 55             getsz(e[k].to,u);
 56             sz[u]+=sz[e[k].to];
 57         }
 58 }
 59 void getdeep(int u,int fa)
 60 {
 61     xx[root].push_back(P(dep[u],nowsec));
 62     for(int k=f1[u];k;k=e[k].nxt)
 63         if(!vis[e[k].to]&&e[k].to!=fa)
 64         {
 65             dep[e[k].to]=dep[u]+e[k].d;
 66             getdeep(e[k].to,u);
 67         }
 68 }
 69 void gdep(LL u)
 70 {
 71     int now=0;xx[root].push_back(P(dep[u],0));
 72     for(int k=f1[u];k;k=e[k].nxt)
 73         if(!vis[e[k].to])
 74         {
 75             dep[e[k].to]=dep[u]+e[k].d;
 76             nowsec=++now;
 77             getdeep(e[k].to,u);
 78         }
 79 }
 80 void solve(int u)
 81 {
 82     vis[u]=1;
 83     for(int k=f1[u];k;k=e[k].nxt)
 84         if(!vis[e[k].to])
 85         {
 86             getsz(e[k].to,0);sum=sz[e[k].to];
 87             root=0;getroot(e[k].to,0);
 88             dep[root]=0;gdep(root);
 89             solve(root);
 90         }
 91 }
 92 int getmaxpos(int i,int l,int r)
 93 {
 94     int t=log2x[r-l+1];
 95     return xx[i][rmq[i][t][l]]>xx[i][rmq[i][t][r-lft[t]+1]] ?
 96         rmq[i][t][l]
 97         :rmq[i][t][r-lft[t]+1];
 98 }
 99 int main()
100 {
101     int i,j,j2,u,v,l,r,pos,nx;Info t;
102     fx[0]=0x3f3f3f3f;lft[0]=1;
103     for(i=1;i<20;i++)    lft[i]=lft[i-1]<<1;
104     for(j=0,i=1;i<=200000;i++)
105     {
106         if(i>=lft[j+1])  ++j;
107         log2x[i]=j;
108     }
109     scanf("%d%d",&n,&k);
110     for(i=1;i<n;i++)
111     {
112         scanf("%d%d%d",&u,&v,&l);
113         e[++ne].to=v;e[ne].nxt=f1[u];e[ne].d=l;f1[u]=ne;
114         e[++ne].to=u;e[ne].nxt=f1[v];e[ne].d=l;f1[v]=ne;
115     }
116     sum=n;getroot(1,0);
117     dep[root]=0;gdep(root);
118     solve(root);
119     for(i=1;i<=n;i++)
120     {
121         nx=xx[i].size();
122         for(j=0;j<19;j++)    rmq[i][j].reserve(nx),rmq[i][j].resize(nx);
123         st.clear();st.reserve(nx);st.resize(nx);
124         ed.clear();ed.reserve(nx);ed.resize(nx);
125         for(j=0;j<nx;j++)    rmq[i][0][j]=j;
126         for(j2=1;j2<19;j2++)
127             for(j=0;j<nx-lft[j2]+1;j++)
128                 if(xx[i][rmq[i][j2-1][j]]>xx[i][rmq[i][j2-1][j+lft[j2-1]]])
129                     rmq[i][j2][j]=rmq[i][j2-1][j];
130                 else
131                     rmq[i][j2][j]=rmq[i][j2-1][j+lft[j2-1]];
132         for(j=0;j<nx;j++)
133         {
134             if(st[xx[i][j].second]==0)
135                 st[xx[i][j].second]=j;
136             ed[xx[i][j].second]=j;
137         }
138         for(j=0;j<nx;j++)
139         {
140             l=st[xx[i][j].second];r=ed[xx[i][j].second];
141             if(l>0)
142             {
143                 pos=getmaxpos(i,0,l-1);
144                 q.push(Info(xx[i][j].first+xx[i][pos].first,i,0,l-1,pos,j));
145             }
146             if(r<nx-1)
147             {
148                 pos=getmaxpos(i,r+1,nx-1);
149                 q.push(Info(xx[i][j].first+xx[i][pos].first,i,r+1,nx-1,pos,j));
150             }
151         }
152     }
153     for(i=1;i<=k;i++)
154     {
155         t=q.top();q.pop();
156         printf("%lld\n",t.ans);
157         if(t.anspos>t.l)
158         {
159             pos=getmaxpos(t.nn,t.l,t.anspos-1);
160             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.l,t.anspos-1,pos,t.pos));
161         }
162         if(t.anspos<t.r)
163         {
164             pos=getmaxpos(t.nn,t.anspos+1,t.r);
165             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.anspos+1,t.r,pos,t.pos));
166         }
167         t=q.top();q.pop();
168         if(t.anspos>t.l)
169         {
170             pos=getmaxpos(t.nn,t.l,t.anspos-1);
171             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.l,t.anspos-1,pos,t.pos));
172         }
173         if(t.anspos<t.r)
174         {
175             pos=getmaxpos(t.nn,t.anspos+1,t.r);
176             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.anspos+1,t.r,pos,t.pos));
177         }
178     }
179     return 0;
180 }
View Code

迫不得已只好换成线段树。。。终于A掉了(说起来新写法最后(x,y)和(y,x)会分别出现一次,要判掉)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<vector>
  4 #include<queue>
  5 #include<map>
  6 using namespace std;
  7 typedef long long LL;
  8 typedef pair<LL,int> P;
  9 struct E
 10 {
 11     int to,nxt,d;
 12 }e[400100];
 13 int f1[200100],n,k,ne;
 14 vector<P> xx[200100];
 15 //表示i点管辖的连通块内各点到自身的距离(second表示子树编号)
 16 vector<int> rmq[200100];
 17 vector<int> st,ed;
 18 //表示i点管辖的连通块内各个子树编号对应的xx内始、终位置
 19 int fx[200100],root,sz[200100],sum,nowsec;
 20 int lft[30],log2x[200100];
 21 LL dep[200010];
 22 bool vis[200100];
 23 struct Info
 24 {
 25     LL ans;int nn,l,r,anspos,pos;
 26     Info(){}
 27     Info(LL a,int b,int c,int d,int e,int f)
 28         :ans(a),nn(b),l(c),r(d),anspos(e),pos(f)
 29     {}
 30     friend bool operator<(const Info &a,const Info &b)
 31     {
 32         return a.ans<b.ans;
 33     }
 34 };
 35 priority_queue<Info> q;
 36 void getroot(int u,int fa)
 37 {
 38     fx[u]=0;sz[u]=1;
 39     for(int k=f1[u];k;k=e[k].nxt)
 40         if(!vis[e[k].to]&&e[k].to!=fa)
 41         {
 42             getroot(e[k].to,u);
 43             fx[u]=max(fx[u],sz[e[k].to]);
 44             sz[u]+=sz[e[k].to];
 45         }
 46     fx[u]=max(fx[u],sum-sz[u]);
 47     if(fx[u]<fx[root])   root=u;
 48 }
 49 void getsz(int u,int fa)
 50 {
 51     sz[u]=1;
 52     for(int k=f1[u];k;k=e[k].nxt)
 53         if(!vis[e[k].to]&&e[k].to!=fa)
 54         {
 55             getsz(e[k].to,u);
 56             sz[u]+=sz[e[k].to];
 57         }
 58 }
 59 void getdeep(int u,int fa)
 60 {
 61     xx[root].push_back(P(dep[u],nowsec));
 62     for(int k=f1[u];k;k=e[k].nxt)
 63         if(!vis[e[k].to]&&e[k].to!=fa)
 64         {
 65             dep[e[k].to]=dep[u]+e[k].d;
 66             getdeep(e[k].to,u);
 67         }
 68 }
 69 void gdep(LL u)
 70 {
 71     int now=0;xx[root].push_back(P(dep[u],0));
 72     for(int k=f1[u];k;k=e[k].nxt)
 73         if(!vis[e[k].to])
 74         {
 75             dep[e[k].to]=dep[u]+e[k].d;
 76             nowsec=++now;
 77             getdeep(e[k].to,u);
 78         }
 79 }
 80 void solve(int u)
 81 {
 82     vis[u]=1;
 83     for(int k=f1[u];k;k=e[k].nxt)
 84         if(!vis[e[k].to])
 85         {
 86             getsz(e[k].to,0);sum=sz[e[k].to];
 87             root=0;getroot(e[k].to,0);
 88             dep[root]=0;gdep(root);
 89             solve(root);
 90         }
 91 }
 92 #define mid ((l+r)>>1)
 93 #define lc (num<<1)
 94 #define rc (num<<1|1)
 95 void build(int i,int l,int r,int num)
 96 {
 97     if(l==r)    {rmq[i][num]=l;return;}
 98     build(i,l,mid,lc);build(i,mid+1,r,rc);
 99     rmq[i][num]=xx[i][rmq[i][lc]]>xx[i][rmq[i][rc]]?rmq[i][lc]:rmq[i][rc];
100 }
101 int L,R;
102 int query(int i,int l,int r,int num)
103 {
104     if(L<=l&&r<=R)    return rmq[i][num];
105     if(L<=mid&&mid<R)
106     {
107         int t1=query(i,l,mid,lc),t2=query(i,mid+1,r,rc);
108         return xx[i][t1]>xx[i][t2]?t1:t2;
109     }
110     else if(L<=mid)  return query(i,l,mid,lc);
111     else if(mid<R)   return query(i,mid+1,r,rc);
112     else    return 0;
113 }
114 int main()
115 {
116     int i,j,j2,u,v,l,r,pos,nx;Info t;
117     fx[0]=0x3f3f3f3f;lft[0]=1;
118     for(i=1;i<30;i++)    lft[i]=lft[i-1]<<1;
119     for(j=0,i=1;i<=200000;i++)
120     {
121         if(i>=lft[j+1])  ++j;
122         log2x[i]=j;
123     }
124     scanf("%d%d",&n,&k);
125     for(i=1;i<n;i++)
126     {
127         scanf("%d%d%d",&u,&v,&l);
128         e[++ne].to=v;e[ne].nxt=f1[u];e[ne].d=l;f1[u]=ne;
129         e[++ne].to=u;e[ne].nxt=f1[v];e[ne].d=l;f1[v]=ne;
130     }
131     sum=n;getroot(1,0);
132     dep[root]=0;gdep(root);
133     solve(root);
134     for(i=1;i<=n;i++)
135     {
136         nx=xx[i].size();
137         st.clear();st.reserve(nx);st.resize(nx);
138         ed.clear();ed.reserve(nx);ed.resize(nx);
139         rmq[i].reserve(lft[log2x[nx]+2]);rmq[i].resize(lft[log2x[nx]+2]);
140         build(i,0,nx-1,1);
141         for(j=0;j<nx;j++)
142         {
143             if(st[xx[i][j].second]==0)
144                 st[xx[i][j].second]=j;
145             ed[xx[i][j].second]=j;
146         }
147         for(j=0;j<nx;j++)
148         {
149             l=st[xx[i][j].second];r=ed[xx[i][j].second];
150             if(l>0)
151             {
152                 L=0,R=l-1,pos=query(i,0,nx-1,1);
153                 q.push(Info(xx[i][j].first+xx[i][pos].first,i,0,l-1,pos,j));
154             }
155             if(r<nx-1)
156             {
157                 L=r+1,R=nx-1,pos=query(i,0,nx-1,1);
158                 q.push(Info(xx[i][j].first+xx[i][pos].first,i,r+1,nx-1,pos,j));
159             }
160         }
161     }
162     for(i=1;i<=k;i++)
163     {
164         t=q.top();q.pop();
165         printf("%lld\n",t.ans);
166         if(t.anspos>t.l)
167         {
168             L=t.l,R=t.anspos-1,pos=query(t.nn,0,xx[t.nn].size()-1,1);
169             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.l,t.anspos-1,pos,t.pos));
170         }
171         if(t.anspos<t.r)
172         {
173             L=t.anspos+1,R=t.r,pos=query(t.nn,0,xx[t.nn].size()-1,1);
174             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.anspos+1,t.r,pos,t.pos));
175         }
176         t=q.top();q.pop();
177         if(t.anspos>t.l)
178         {
179             L=t.l,R=t.anspos-1,pos=query(t.nn,0,xx[t.nn].size()-1,1);
180             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.l,t.anspos-1,pos,t.pos));
181         }
182         if(t.anspos<t.r)
183         {
184             L=t.anspos+1,R=t.r,pos=query(t.nn,0,xx[t.nn].size()-1,1);
185             q.push(Info(xx[t.nn][t.pos].first+xx[t.nn][pos].first,t.nn,t.anspos+1,t.r,pos,t.pos));
186         }
187     }
188     return 0;
189 }

还有两点:

1.这题还有一个写法,就是先二分答案找第k大(由于判断价值小于某个给定值的点对数可以用点分容斥做,比较容易),然后再一遍点分把小于这个第k大的全部搞出来(好像是启发式)

2.按照我这个写法,好像可以把各个vector并到一个数组里,然后st表,就不会MLE了

posted @ 2018-03-20 18:19  hehe_54321  阅读(242)  评论(0编辑  收藏  举报
AmazingCounters.com