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

luogu P8349 [SDOI/SXOI2022] 整数序列

题面传送门
怎么比ZJOI想的时间还长/fn/fn
但是感觉现有的题解为啥都要根号分治啊,这个东西本身的复杂度很优美啊。
首先有一个单次O(lenx+leny)的暴力但是不太妙。
考虑如果有一个颜色只有一个数另一个有很多个数,那么除了一个数左右各一个另一种颜色其它都是没有用的。
这启发我们猜想:对于一个较少的颜色,是否只有左右各一倍内的另一种颜色是有用的。
每次对个数比较少的颜色拿出来做,看这个颜色两个相邻点之间的另一种颜色个数与这两个相邻点分别向左和向右的最大前缀比较,如果大于那么这一段会使左右两边断开,那么对左边有用的点的个数只有左边的最大前缀的个数,对右边同理。
所以我们有了一个O(min(lenx,leny))的做法。
但是这个做法显然不对,如果就两种颜色每种占O(n2)然后多次询问两种一样的颜色那不是直接咕咕。
然后你写了一发记忆化发现交上去过了?
时间复杂度其实可以证明是O(nq)。考虑对于一种颜色,它的个数在所有颜色中从大到小排名第k,则它的大小不会超过nk。要想卡满询问肯定是从大到小问,那么每增加O(n)的运算次数都要比上一次加一个询问。所以时间复杂度上界是O(nq)
虽然但是我偷懒写了个O(nqlogn)的二分。但是是真的好写跑得也不慢。
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 ll long long
#define db double
#define lb long db
#define N (300000+5)
#define M (5000000-5)
#define K (1500+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#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) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
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;
using namespace std;vector<int> Id[N];map<int,ll> F[N];
int n,m,k,z,x,y,A[N],B[N],Q[N],P1[N],P2[N],C[N],H;ll Ans,Ts,D[N],Fl[N<<1];
I ll Solve(){int i;ll Ans=-1e18;for(i=1;i<=2*H;i++) Fl[i]=1e18;Fl[H]=0;for(i=1;i<=H;i++) C[i]+=C[i-1],D[i]+=D[i-1],Ans=max(Ans,D[i]-Fl[C[i]+H]),Fl[C[i]+H]=min(Fl[C[i]+H],D[i]);H=0;return Ans;}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int i,j,h;fin>>n>>m;k=n/sqrt(m/log2(n));for(i=1;i<=n;i++) Id[i].PB(0);for(i=1;i<=n;i++) fin>>A[i],Id[A[i]].PB(i);for(i=1;i<=n;i++) fin>>B[i];
	while(m--){fin>>x>>y;Id[x].size()>Id[y].size()&&(swap(x,y),0);if(F[x].count(y)){fout<<F[x][y]<<'\n';continue;}Q[0]=0;Q[(int)Id[x].size()]=Id[y].size()-1;
		if(Id[y].size()<=k) for(j=1;j<Id[x].size();j++) {Q[j]=Q[j-1];while(Q[j]<Id[y].size()-1&&Id[y][Q[j]+1]<Id[x][j]) Q[j]++;}else for(j=1;j<Id[x].size();j++) Q[j]=LB(Id[y].begin(),Id[y].end(),Id[x][j])-Id[y].begin()-1;
		P1[0]=0;for(j=1;j<Id[x].size();j++) P1[j]=max(P1[j-1]+Q[j-1]-Q[j]+1,1);P2[(int)Id[x].size()]=0;for(j=Id[x].size()-1;j;j--) P2[j]=max(1,P2[j+1]+Q[j]-Q[j+1]+1);
		Ans=-1e18;H=0;for(j=1;j<=Id[x].size();j++) {j^1&&(C[++H]=1,D[H]=B[Id[x][j-1]]);
			if(P1[j-1]+P2[j]<Q[j]-Q[j-1]){for(h=Q[j-1]+1;h<Q[j-1]+1+P1[j-1];h++) C[++H]=-1,D[H]=B[Id[y][h]];Ts=Solve();Ans=max(Ans,Ts);for(h=Q[j]-P2[j]+1;h<=Q[j];h++) C[++H]=-1,D[H]=B[Id[y][h]];continue;}
			for(h=Q[j-1]+1;h<=Q[j];h++) C[++H]=-1,D[H]=B[Id[y][h]];
		}Ts=Solve();Ans=max(Ans,Ts);fout<<(F[x][y]=Ans)<<'\n';
	}
} 
posted @   275307894a  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-06-12 luogu P5052 [COCI2017-2018#7] Go
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示