BZOJ4553: [Tjoi2016&Heoi2016]序列
Description
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值
可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你
,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可
。注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 31 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:3 3 33 2 3选择子序列
为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求
Input
输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的
状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。所有数字均为正整数
,且小于等于100,000
Output
输出一个整数,表示对应的答案
Sample Input
3 4
1 2 3
1 2
2 3
2 1
3 4
1 2 3
1 2
2 3
2 1
3 4
Sample Output
3
设B[i]表示A[i]能变成的最大值,C[i]表示A[i]能变成的最小值,然后就可以DP了。
f[i]=max(f[j]|B[j]<=A[i]&&A[j]<=C[i])+1,不难发现是一个三维偏序结构。
首先我写了个线段树套线段树,然后被精妙地卡内存了。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; const int maxnode=13000010; const int inf=1e9; int n,m,ans,A[maxn],B[maxn],C[maxn],f[maxn]; int root[maxn<<2],maxv[maxnode],ls[maxnode],rs[maxnode],ToT; void insert(int& o,int l,int r,int p,int val) { if(!o) o=++ToT;maxv[o]=max(maxv[o],val); if(l==r) return;int mid=l+r>>1; if(p<=mid) insert(ls[o],l,mid,p,val); else insert(rs[o],mid+1,r,p,val); } void insert(int o,int l,int r,int x,int y,int val) { insert(root[o],1,100000,y,val);if(l==r) return; int mid=l+r>>1,lc=o<<1,rc=lc|1; if(x<=mid) insert(lc,l,mid,x,y,val); else insert(rc,mid+1,r,x,y,val); } int query(int o,int l,int r,int p) { if(!o) return 0; if(l==r) return maxv[o]; int mid=l+r>>1; if(p<=mid) return query(ls[o],l,mid,p); return max(maxv[ls[o]],query(rs[o],mid+1,r,p)); } int query(int o,int l,int r,int x,int y) { if(l==r) return query(root[o],1,100000,y); int mid=l+r>>1,lc=o<<1,rc=lc|1; if(x<=mid) return query(lc,l,mid,x,y); return max(query(root[lc],1,100000,y),query(rc,mid+1,r,x,y)); } int main() { n=read();m=read(); rep(i,1,n) A[i]=B[i]=C[i]=read(); rep(i,1,m) { int x=read(),y=read(); B[x]=max(B[x],y); C[x]=min(C[x],y); } rep(i,1,n) { f[i]=query(1,1,100000,A[i],C[i])+1; insert(1,1,100000,B[i],A[i],f[i]); ans=max(ans,f[i]); } printf("%d\n",ans); return 0; }
然后写了个kd树,跑得真是慢。。。
#include<cstdio> #include<cctype> #include<set> #include<cstring> #include<algorithm> #define L T[o].lc #define R T[o].rc #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; const int inf=1e9; int D,n,m,ans,A[maxn],B[maxn],C[maxn],f[maxn]; struct Node { int x[2],mx[2],mn[2],lc,rc,val,maxv; bool operator < (const Node& ths) const {return x[D]<ths.x[D]||(x[D]==ths.x[D]&&x[D^1]<ths.x[D^1]);} }T[maxn],P; void maintain(int o) {T[o].maxv=max(T[o].val,max(T[L].maxv,T[R].maxv));} void build(int& o,int l,int r,int cur) { int mid=l+r>>1;D=cur;o=mid;nth_element(T+l,T+mid,T+r+1); if(l<mid) build(L,l,mid-1,cur^1); if(mid<r) build(R,mid+1,r,cur^1); rep(c,0,1) { T[o].mn[c]=min(T[o].x[c],min(T[L].mn[c],T[R].mn[c])); T[o].mx[c]=max(T[o].x[c],max(T[L].mx[c],T[R].mx[c])); } } int query(int o) { if(!o) return 0; if(T[o].mn[0]>P.x[0]||T[o].mn[1]>P.x[1]) return 0; if(T[o].mx[0]<=P.x[0]&&T[o].mx[1]<=P.x[1]) return T[o].maxv; int ans=0; if(T[o].x[0]<=P.x[0]&&T[o].x[1]<=P.x[1]) ans=T[o].val; return max(ans,max(query(L),query(R))); } void insert(int o,int cur,int val) { if(T[o].x[0]==P.x[0]&&T[o].x[1]==P.x[1]) T[o].val=max(T[o].val,val); else { D=cur;insert(P<T[o]?L:R,cur^1,val); } maintain(o); } int main() { T[0].mn[0]=T[0].mn[1]=inf; T[0].mx[0]=T[0].mx[1]=-inf; n=read();m=read();int rt=0; rep(i,1,n) A[i]=B[i]=C[i]=read(); rep(i,1,m) { int x=read(),y=read(); B[x]=max(B[x],y); C[x]=min(C[x],y); } rep(i,1,n) T[i].x[0]=B[i],T[i].x[1]=A[i]; build(rt,1,n,0); rep(i,1,n) { P.x[0]=A[i];P.x[1]=C[i]; f[i]=query(rt)+1; P.x[0]=B[i];P.x[1]=A[i]; insert(rt,0,f[i]); ans=max(ans,f[i]); } printf("%d\n",ans); return 0; }