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 }
想想都知道不对啊。。。复杂度肯定不对的啊。。。。。毫不意外地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 }
迫不得已只好换成线段树。。。终于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了