【浮*光】#省选真题# [SCOI2015]
就比较随性的记录一下啦啦啦啦啦啦啦 . . . . . .
T1:【p4155】国旗计划 // 贪心 + 倍增
#include <cmath> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; /*【p4155】国旗计划 // 贪心 + 倍增 */ void reads(uint &x){ //读入优化(正负整数) uint fx_=1;x=0;char ch_=getchar(); while(ch_<'0'||ch_>'9'){if(ch_=='-')fx_=-1;ch_=getchar();} while(ch_>='0'&&ch_<='9'){x=x*10+ch_-'0';ch_=getchar();} x*=fx_; //正负号 } const uint N=200019; struct Seg{ uint l,r,id; //记录线段(区间),并不是segment_tree Seg(uint a=0,uint b=0,uint c=0):l(a),r(b),id(c){} //↓↓按左端点排序(区间无重叠) friend bool operator < (const Seg &a,const Seg &b){return a.l<b.l;} }seg[N<<1]; int mul[19][N<<1],ans[N]; uint n,m; void Init(){ sort(seg+1,seg+1+2*n); int pit=0; seg[2*n+1]=Seg(-1,-1); //设定外部终点 for(int i=1;i<=2*n;i++) //维护一个指针,假如指针指向区间与当前区间有交集,就让指针右移 //不断重复至某个与当前区间无交集的区间,那么它的前一个区间就是需要‘贪心’选取的区间 { while(seg[pit+1].l<=seg[i].r) pit++; mul[0][i]=pit; } for(int j=1;j<=18;j++) for(int i=1;i<=2*n;i++) mul[j][i]=mul[j-1][mul[j-1][i]]; seg[0]=Seg(-1,-1); // ↑↑ 倍增记录相关选择过程,并设置外部起点 } int main(){ reads(n),reads(m); for(int i=1;i<=n;i++){ uint l,r; reads(l),reads(r); if(l<=r) seg[i]=Seg(l,r,i),seg[n+i]=Seg(m+l,m+r); else seg[i]=Seg(l,m+r,i),seg[n+i]=Seg(m+l,m*2+r); } Init(); //设置起点终点、求倍增区间 for(int i=1;i<=2*n;i++){ if(!seg[i].id) continue; int pit=i,res=2; for(int j=18;j>=0;j--) if(seg[mul[j][pit]].r-seg[i].l<m) pit=mul[j][pit],res+=1<<j; ans[seg[i].id]=res; //记录此时需要的选择个数res } for(int i=1;i<=n;i++) cout<<ans[i]<<" "; cout<<endl; }
T2:【p4216】情报传递 // 树剖 + 主席树/线段树
#include <cmath> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; /*【p4216】情报传递 // 树剖 + 主席树/线段树 */ /*【分析】将每个情报员开始搜集情报的时刻设为它的权值c。 对于一个始终没有搜集情报的人,权值设为Q(询问的个数)。 对于t时刻的询问,就转化为询问路径上比t-c小的值有多少个。 */ void reads(int &x){ //读入优化(正负整数) int fx_=1;x=0;char ch_=getchar(); while(ch_<'0'||ch_>'9'){if(ch_=='-')fx_=-1;ch_=getchar();} while(ch_>='0'&&ch_<='9'){x=x*10+ch_-'0';ch_=getchar();} x*=fx_; //正负号 } #define lson (rt<<1) #define rson (rt<<1|1) const int maxn=200000+10; int n,m,rt,head[maxn],ver[maxn<<1],nextt[maxn<<1],tot; int top[maxn],dep[maxn],son[maxn],fa[maxn],siz[maxn],id[maxn],rev[maxn],tim; vector<int> v[maxn<<2]; void update(int x,int C,int l,int r,int rt){ v[rt].push_back(C); if(l==r) return ; int mid=(l+r)>>1; if(x<=mid) update(x,C,l,mid,lson); else update(x,C,mid+1,r,rson); } int query(int L,int R,int C,int l,int r,int rt){ if(L<=l&&r<=R){ vector<int>::iterator it=upper_bound(v[rt].begin(),v[rt].end(),C); return it-v[rt].begin(); //↑↑暴力二分查找 } int mid=(l+r)>>1,ans=0; if(L<=mid) ans+=query(L,R,C,l,mid,lson); if(R>mid) ans+=query(L,R,C,mid+1,r,rson); return ans; } void add_(int x,int y){ ver[++tot]=y,nextt[tot]=head[x],head[x]=tot; } void dfs1(int x,int fa_){ siz[x]=1,fa[x]=fa_,dep[x]=dep[fa_]+1; int maxson=-1; for(int i=head[x],y;i;i=nextt[i]){ y=ver[i]; if(y==fa_) continue; dfs1(y,x),siz[x]+=siz[y]; if(siz[y]>maxson) maxson=siz[y],son[x]=y; } } void dfs2(int x,int topf){ id[x]=++tim,rev[tim]=x,top[x]=topf; if(son[x]) dfs2(son[x],topf); for(int i=head[x],y;i;i=nextt[i]) { y=ver[i]; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } inline void ask(int x,int y,int z){ int ans1=0,ans2=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ans1+=id[x]-id[top[x]]+1; ans2+=query(id[top[x]],id[x],z,1,n,1),x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); ans1+=id[y]-id[x]+1,ans2+=query(id[x],id[y],z,1,n,1); printf("%d %d\n",ans1,ans2); } int main(){ reads(n); for(int i=1,x;i<=n;i++) { reads(x); if(!x) rt=i; else add_(x,i); } dfs1(rt,0),dfs2(rt,rt); reads(m); for(int i=1,op,x,y,z;i<=m;i++){ reads(op),reads(x); if(op==1) reads(y),reads(z),ask(x,y,i-z-1); //查询可行性 if(op==2) update(id[x],i,1,n,1); /* 修改x节点对应的权值 */ } }
T3:【p4216】情报传递 // 树剖 + 主席树/线段树