题目分析:
权值第k小很好处理,整体二分就可以了。
再一看路径包含,什么玩意??
然后就被dalao的分析震惊了
居然可以转化成dfs序,判断x,y路径在盘子子树内、子树外。
若x与y不成祖先-孩子关系,则包含它的路径u-v满足:起点在x的子树里,且终点在y的子树里。
若x与y成祖先-孩子关系,假设y是x的祖先,z是y到x方向的第一个节点,则包含它的路径u-v满足:起点在x的子树里,且终点不在z的子树里。
我就只补充一下怎么求一个点被矩形覆盖的次数。
这是个二维偏序问题,一维排序,一维树状数组就可以解决了
具体做法就是把,把一个矩形变成两条在x1,x2处的两条(y1,y2)线段,然后把矩形和询问都按照x轴排序,矩形的y轴线段在树状数组中差分。查询就直接按y查树状数组。
Code:
#include<cstdio>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
#define maxn 40005
#define LL long long
using namespace std;
inline void read(int &a){
char c;bool f=0;
while(!isdigit(c=getchar())) if(c=='-') f=1;
for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
if(f) a=-a;
}
int n,m,Q,cnt,ans[maxn],sum[maxn];
int in[maxn],out[maxn],tim,f[maxn][20],dep[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
struct matrix{
int x1,x2,y1,y2,val;
bool operator < (const matrix &p)const{return val<p.val;}
}a[maxn<<1],b[maxn<<2];
bool cmpx(const matrix &a,const matrix &b){return a.x1<b.x1;}
struct node{
int x,y,id,k;
bool operator < (const node &p)const{return x<p.x;}
}q[maxn],qt[maxn];
inline void line(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
void dfs(int u){
in[u]=++tim;
for(int i=fir[u];i;i=nxt[i])
if(!in[to[i]]) f[to[i]][0]=u,dep[to[i]]=dep[u]+1,dfs(to[i]);
out[u]=tim;
}
int find(int u,int v){
int k=dep[u]-dep[v]-1;
for(int i=17;i>=0;i--) if(k&(1<<i)) u=f[u][i];
return u;
}
int arr[maxn];
void update(int i,int d){for(;i<=n;i+=i&-i) arr[i]+=d;}
int getsum(int i){int s=0;for(;i;i-=i&-i) s+=arr[i];return s;}
void calc(int h,int t,int vl,int vr){
for(int i=h;i<=t;i++) sum[i]=0;
int l=lower_bound(a+1,a+1+cnt,(matrix){0,0,0,0,vl})-a,num=0;
if(l>cnt) return;
for(int i=l;i<=cnt&&a[i].val<=vr;i++){
b[++num]=(matrix){a[i].x1,0,a[i].y1,a[i].y2,1};
b[++num]=(matrix){a[i].x2+1,0,a[i].y1,a[i].y2,-1};
}
sort(b+1,b+1+num,cmpx);
for(int i=1,j=h;i<=num||j<=t;){
int x=i>num?q[j].x:j>t?b[i].x1:min(b[i].x1,q[j].x);
while(i<=num&&b[i].x1<=x) update(b[i].y1,b[i].val),update(b[i].y2+1,-b[i].val),i++;
while(j<=t&&q[j].x<=x) sum[j]=getsum(q[j].y),j++;
}
}
void solve(int h,int t,int vl,int vr){
if(h>t) return;
if(vl==vr) {for(int i=h;i<=t;i++) ans[q[i].id]=vl;return;}
int vmid=(vl+vr)>>1;
calc(h,t,vl,vmid);
int st=h-1;
for(int i=h;i<=t;i++) if(q[i].k<=sum[i]) qt[++st]=q[i];
int mid=st;
for(int i=h;i<=t;i++) if(q[i].k>sum[i]) q[i].k-=sum[i],qt[++st]=q[i];
for(int i=h;i<=t;i++) q[i]=qt[i];
solve(h,mid,vl,vmid),solve(mid+1,t,vmid+1,vr);
}
int main()
{
int x,y,z,w;
read(n),read(m),read(Q);
for(int i=1;i<n;i++) read(x),read(y),line(x,y),line(y,x);
dfs(1);
for(int j=1;j<=17;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=m;i++){
read(x),read(y),read(w);
if(in[x]>in[y]) swap(x,y);
if(in[x]<=in[y]&&out[y]<=out[x]){
z=find(y,x);
if(in[z]>1) a[++cnt]=(matrix){1,in[z]-1,in[y],out[y],w};
if(out[z]<n) a[++cnt]=(matrix){in[y],out[y],out[z]+1,n,w};
}
else a[++cnt]=(matrix){in[x],out[x],in[y],out[y],w};
}
for(int i=1;i<=Q;i++){
read(x),read(y),read(q[i].k),q[i].id=i;
q[i].x=min(in[x],in[y]),q[i].y=max(in[x],in[y]);
}
sort(a+1,a+1+cnt);
sort(q+1,q+1+Q);
solve(1,Q,0,1e9);
for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}
一开始打的时候把矩形直接放到了vector里面每次O(n)循环,没有用排序,然而复杂度是不对的,整体二分是一层的总和O(n),而不是一段O(n),TLE到爆炸。。