bzoj3551 Peaks加强版

这个题……感觉离线和在线的代码难度差不多(pb_ds不要说话)。

离线的话,就是把所有询问按照w排个序,然后一边Kruskal+平衡树启发式合并一边回答询问就好了。

在线也不难写。首先Kruskal重构树(这个Kruskal重构树是不按秩合并还要添虚点的那种……),那么每个点可以到达的点一定在某个子树里。子树的dfs序是连续的,所以可以对dfs序建主席树来求区间k大。又因为只有叶子节点的点权是有意义的,所以可以只对叶子的dfs序建主席树。查询的时候倍增跳到最高的w<=询问的w的点然后主席树就好了。

其实树剖跳父亲也可以,先跳整条链,整条链跳不动的时候就在最后一条链上二分,也是O(logn)的。不过可能是太弱,二分写挂了,结果WA到死……无奈用倍增重写了一遍。

限时20s,结果我跑了19.8s,这速度真是感人肺腑……

还有,copy的那个a一开始忘了+1了,调了一节课,虚死……

  1 /**************************************************************
  2     Problem: 3551
  3     User: hzoier
  4     Language: C++
  5     Result: Accepted
  6     Time:19800 ms
  7     Memory:114432 kb
  8 ****************************************************************/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 using namespace std;
 13 const int maxn=200010,maxe=500010;
 14 struct edge{
 15     int from,to,w;
 16     bool operator<(const edge &e)const{return w<e.w;}
 17 }e[maxe+maxn];
 18 void Kruskal();
 19 int findroot(int);
 20 void mergeset(int,int);
 21 void dfs(int);
 22 void build(int,int,int&,int);
 23 void query(int,int,int,int);
 24 int sm[maxn<<5],lc[maxn<<5],rc[maxn<<5],root[maxn],tree_cnt=0;
 25 int n,M=0,m,q,h[maxn],a[maxn],cnt,prt[maxn],w[maxn],f[maxn][20],ch[maxn][2],L[maxn],R[maxn],pr=0,x,d,k,ans;
 26 int main(){
 27     scanf("%d%d%d",&n,&m,&q);
 28     while((1<<M)<(n<<1))M++;
 29     for(int i=1;i<=n;i++)scanf("%d",&h[i]);
 30     copy(h+1,h+n+1,a+1);
 31     sort(a+1,a+n+1);
 32     for(int i=1;i<=n;i++)h[i]=lower_bound(a+1,a+n+1,h[i])-a;
 33     for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w);
 34     for(int i=2;i<=n;i++){
 35         e[++m].from=1;
 36         e[m].to=i;
 37         e[m].w=~(1<<31);
 38     }
 39     cnt=n;
 40     Kruskal();
 41     dfs(cnt);
 42     for(int j=1;j<=M;j++)for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1];
 43     while(q--){
 44         scanf("%d%d%d",&x,&d,&k);
 45         if(ans!=-1){x^=ans;d^=ans;k^=ans;}
 46         for(int j=M;j!=-1;j--)if(f[x][j]&&w[f[x][j]]<=d)x=f[x][j];
 47         query(1,n,root[R[x]],root[L[x]-1]);
 48         printf("%d\n",ans);
 49     }
 50     return 0;
 51 }
 52 void Kruskal(){
 53     for(int i=1;i<=n;i++)prt[i]=i;
 54     stable_sort(e+1,e+m+1);
 55     for(int i=1;i<=m;i++)if(findroot(e[i].from)!=findroot(e[i].to)){
 56         cnt++;
 57         prt[cnt]=cnt;
 58         w[cnt]=e[i].w;
 59         ch[cnt][0]=findroot(e[i].from);
 60         ch[cnt][1]=findroot(e[i].to);
 61         mergeset(e[i].from,cnt);
 62         mergeset(e[i].to,cnt);
 63     }
 64 }
 65 int findroot(int x){return prt[x]==x?x:(prt[x]=findroot(prt[x]));}
 66 void mergeset(int x,int y){prt[findroot(x)]=findroot(y);}
 67 void dfs(int x){
 68     if(ch[x][0]){
 69         f[ch[x][0]][0]=f[ch[x][1]][0]=x;
 70         dfs(ch[x][0]);
 71         dfs(ch[x][1]);
 72         L[x]=L[ch[x][0]];
 73         R[x]=R[ch[x][1]];
 74     }
 75     else{
 76         k=h[x];
 77         build(1,n,root[pr+1],root[pr]);
 78         L[x]=R[x]=++pr;
 79     }
 80 }
 81 void build(int l,int r,int &rt,int pr){
 82     sm[rt=++tree_cnt]=sm[pr]+1;
 83     if(l==r)return;
 84     lc[rt]=lc[pr];rc[rt]=rc[pr];
 85     int mid=(l+r)>>1;
 86     if(k<=mid)build(l,mid,lc[rt],lc[pr]);
 87     else build(mid+1,r,rc[rt],rc[pr]);
 88 }
 89 void query(int l,int r,int rt,int pr){
 90     if(sm[rt]-sm[pr]<k){
 91         ans=-1;
 92         return;
 93     }
 94     if(l==r){
 95         ans=a[l];
 96         return;
 97     }
 98     int mid=(l+r)>>1;
 99     if(k<=sm[rc[rt]]-sm[rc[pr]])query(mid+1,r,rc[rt],rc[pr]);
100     else{
101         k-=sm[rc[rt]]-sm[rc[pr]];
102         query(l,mid,lc[rt],lc[pr]);
103     }
104 }
View Code

 

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

转载于:https://www.cnblogs.com/hzoier/p/6056980.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值