把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4632 [APIO2018] New Home 新家

题面传送门
首先最大值最小肯定想到二分。
然后二分相当于问一个区间是不是有\(k\)种颜色。
一个简单粗暴的想法就是树套树算有几种颜色,\(O(n\log^3n)\),能过就有鬼了。
发现如果后面有一个点的前驱在这个区间以前,那么一定有一种颜色没有出现过。
所以只要维护主席树维护后缀min,然后询问的时候二分就好了。
但是这个直接卡常卡飞了。主席树比离散的二分慢了10倍。
其实是不用主席树的,直接把询问离线然后扔到对应节点就好了。
然后就快得多。
时间复杂度\(O(n\log ^2n)\),感觉可以线段树上二分做到一个log,但是没啥必要。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (300000+5)
#define M (400000+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;set<int> F[N];set<int>::it P1,P2;
int n,m,k,Ht,x,y,l,r,mid,Ans[N],Ts[N<<1],La,Ls,Ne,Ns[N],Ct[N],Hn,X[N],T[N],A[N],B[N],Ro[N<<1];
struct IO{
    static const int S=1<<21;
    char buf[S],*p1,*p2;int st[105],Top;
    ~IO(){clear();}
    inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
    inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
    inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
    template<typename T>inline IO&operator >> (T&x){
        x=0;bool f=0;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
        f?x=-x:0;return *this;
    }
    inline IO&operator << (const char c){pc(c);return *this;}
    template<typename T>inline IO&operator << (T x){
        if(x<0) pc('-'),x=-x;
        do{st[++st[0]]=x%10,x/=10;}while(x);
        while(st[0]) pc('0'+st[st[0]--]);return *this;
    }
}fin,fout;
namespace Tree{
	#define ls now<<1
	#define rs now<<1|1
	int F[N<<3];I void Up(int now){F[now]=min(F[ls],F[rs]);}
	I void BD(int l=1,int r=Hn+m,int now=1){if(l==r){F[now]=(l<=Hn?1e9:0);return;}int m=l+r>>1;BD(l,m,ls);BD(m+1,r,rs);Up(now);}
	I void Ins(int x,int y,int l=1,int r=Hn+m,int now=1){if(l==r){F[now]=y;return;}int m=l+r>>1;x<=m?Ins(x,y,l,m,ls):Ins(x,y,m+1,r,rs);Up(now);}
	I int Qry(int x,int y,int l=1,int r=Hn+m,int now=1){if(x<=l&&r<=y) return F[now];int m=l+r>>1,F1=1e9,F2=1e9;x<=m&&(F1=Qry(x,y,l,m,ls));y>m&&(F2=Qry(x,y,m+1,r,rs));return min(F1,F2);}
	#undef ls
	#undef rs
}
struct Ques{int x,y;};vector<Ques> Is[N<<1],Dl[N<<1],Q[N<<1];
I int CK(int mid,int x){return Tree::Qry(UB(Ns+1,Ns+Hn+1,x+mid)-Ns,Hn+m)>=LB(Ns+1,Ns+Hn+1,x-mid)-Ns;}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	RI i;fin>>n>>m>>k;for(i=1;i<=n;i++) fin>>X[i]>>T[i]>>A[i]>>B[i],Ts[++Ht]=A[i],Ts[++Ht]=B[i]+1;sort(Ts+1,Ts+Ht+1);Ht=unique(Ts+1,Ts+Ht+1)-Ts-1;
	for(i=1;i<=n;i++) A[i]=LB(Ts+1,Ts+Ht+1,A[i])-Ts,B[i]=LB(Ts+1,Ts+Ht+1,B[i]+1)-Ts;for(i=1;i<=n;i++)Ns[++Hn]=X[i];sort(Ns+1,Ns+Hn+1);Tree::BD();
	for(i=1;i<=n;i++) X[i]=LB(Ns+1,Ns+Hn+1,X[i])-Ns,X[i]=X[i]+(Ct[X[i]]++),Is[A[i]].PB((Ques){X[i],T[i]}),Dl[B[i]].PB((Ques){X[i],T[i]});for(i=1;i<=m;i++) F[i].insert(0),F[i].insert(Hn+i);
	for(i=1;i<=k;i++){fin>>x>>y;y=UB(Ts+1,Ts+Ht+1,y)-Ts-1;Q[y].PB((Ques){x,i});}for(i=0;i<=Ht;i++) {
		for(Ques d:Is[i]) P1=F[d.y].LB(d.x),Tree::Ins(*P1,d.x),P1--,Tree::Ins(d.x,*P1),F[d.y].insert(d.x);
		for(Ques d:Dl[i]) F[d.y].erase(d.x),P1=F[d.y].LB(d.x),Tree::Ins(d.x,1e9),P2=P1,P2--,Tree::Ins(*P1,*P2); 
		for(Ques d:Q[i]) {l=-1;r=1e8+1;while(l+1<r) mid=l+r>>1,(CK(mid,d.x)?r:l)=mid;Ans[d.y]=(r>1e8?-1:r);}
	}for(i=1;i<=k;i++) printf("%d\n",Ans[i]);
}
posted @ 2022-03-18 20:45  275307894a  阅读(22)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end