bzoj3551
2016-04-28 21:22
211 查看
3551: [ONTAK2010]Peaks加强版
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 877 Solved: 297
[Submit][Status][Discuss]
Description
【题目描述】同3545Input
第一行三个数N,M,Q。第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1则不变。
Output
同3545Sample Input
Sample Output
HINT
【数据范围】同3545Source
题解:过了这么久才又开始写博客(省选被虐成渣,现在还要准备半期考试 only shit)好吧,算了毕竟太渣,不多说了,写题解QAQ
看了题目,一脸懵逼,怎么写?(不会) 怎么办?(看题解)
首先看看这道题,它是一个无向图,根本不知道怎么来写主席树,操蛋。
仔细看看题,我们可以这样想,我要走一个边权比x小的边,并且一直走下去,我们不就可以用最小生成树吗?每次走最小的边,那么一定是最优的,所以我们就用kruskal来写
但是要注意的是,在找到一个新的边时,新建一个节点,权值为边的权值,把边的两端连向这个点,不难证明这是一课树。。。。。
然后每次询问就从当前点往上面倍增地跳,直到不能走(点权大于x) 那么那个点的子树中的点就是我可以到达的点
于是题目就变成求一个子树第k大的问题。。。用lca加和主席树就A了
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #define maxn 300005 #define maxnode 2000005 using namespace std; int n,m,q,lastans,top; int size,tot,ext; int pre[maxn],now[maxn],v[maxn],fa[maxn],sum[maxnode],son[maxnode][2],pp[maxn]; int bin[20],deep[maxn],f[maxn][20],mx[maxn][20]; int h[maxn],list[maxn],qz[maxn],root[maxn],st[maxn],ed[maxn]; bool vis[maxn]; struct date{int u,v,val; }a[500005]; int read() { int x=0; char ch; bool bo=0; while (ch=getchar(),ch<'0'||ch>'9') if (bo=='-') bo=1; while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); if (bo) return -x; return x; } bool cmp_val(date a, date b) { return a.val<b.val; } int find(int x) { if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void insert(int x,int y){tot++; pre[tot]=now[x]; now[x]=tot; v[tot]=y; } void ins(int l,int r,int x,int &y,int val) { int t; if (!y) y=++tot; sum[y]=sum[x]+1; if (l==r) return; int mid=(l+r)>>1; if (val<=mid) t=0,r=mid; else t=1,l=mid+1; son[y][t^1]=son[x][t^1]; ins(l,r,son[x][t],son[y][t],val); } void dfs(int x) { vis[x]=1; pp[++top]=x; for (int i=1; i<=16; i++) if (bin[i]<=deep[x]) { f[x][i]=f[f[x][i-1]][i-1]; mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]); } for (int p=now[x]; p; p=pre[p]) { int son=v[p]; deep[son]=deep[x]+1; f[son][0]=x; mx[son][0]=qz[x]; dfs(son); } if (x>n) pp[++top]=x; } void build() { ext=n; sort(a+1,a+m+1,cmp_val); for (int i=1; i<=m; i++) { int q=find(a[i].u),p=find(a[i].v); if (q!=p) { ext++; fa[q]=fa[p]=ext; qz[ext]=a[i].val; insert(ext,p); insert(ext,q); if (ext==2*n-1) break; } } for (int i=1; i<=n; i++) { if (!vis[i]) dfs(find(i)); } for (int i=1; i<=top; i++) { int t=pp[i]; if (t<=n) ins(1,n,root[i-1],root[i],h[t]); else { root[i]=root[i-1]; if (!st[t]) st[t]=i; else ed[t]=i; } } } int valfind(int x,int val) { for(int i=17;i>=0;i--) if(deep[x]>=bin[i]&&mx[x][i]<=val)x=f[x][i]; return x; } int query(int l,int r,int x,int y,int val) { if (l==r) return l; int mid=(l+r)>>1; int kk=sum[son[y][0]]-sum[son[x][0]],t; //cout<<" "<<kk<<endl; if (kk>=val) return query(l,mid,son[x][0],son[y][0],val); else return query(mid+1,r,son[x][1],son[y][1],val-kk); } void solve() { while (q--) { int x=read(),val=read(),k=read(); if (lastans!=-1) x^=lastans,val^=lastans,k^=lastans; int t=valfind(x,val); int a=root[st[t]],b=root[ed[t]]; if (sum[b]-sum[a]<k) lastans=-1; else lastans=list[query(1,n,a,b,sum[b]-sum[a]-k+1)]; printf("%d\n",lastans); } } void prework() { bin[0]=1; for (int i=1; i<20; i++) bin[i]=bin[i-1]<<1; for (int i=1; i<=2*n; i++) fa[i]=i; sort(list+1,list+1+n); for (int i=1; i<=n; i++) h[i]=lower_bound(list+1,list+1+n,h[i])-list; for (int i=1; i<=m; i++) { a[i].u=read(); a[i].v=read(); a[i].val=read(); } build(); } int main() { n=read(); m=read(); q=read(); for (int i=1; i<=n; i++) list[i]=h[i]=read(); prework(); solve(); return 0; }
View Code
相关文章推荐
- 页面的CSS属性
- 【感悟】寻找生命的意义
- 计算日期天数差值
- Java基础
- 自己去搭建一整套的代价足够大,不如会快捷使用它
- 微型Top源码剖析
- Ubuntu 安装 lnmp
- 【Docker】容器、虚拟机与Docker概念全解析
- MVC 下 JsonResult 的使用方法(JsonRequestBehavior.AllowGet)【转】
- 有关Java继承的一小段代码
- 【2016.4.23】【gdoi2016前模拟赛】【总结】
- HDU 2767 Proving Equivalences 强连通分量
- iOS开发总结之UIView常用属性
- SNS进阶
- 第九周 周记
- centos 6.5环境利用iscsi搭建SAN网络存储服务及服务端target和客户端initiator配置详解
- C语言的学习
- XDU-1036 分配宝藏 (DP)
- centos 6.5环境利用iscsi搭建SAN网络存储服务及服务端target和客户端initiator配置详解
- NOIP199904求Cantor表