• P4477 【[BJWC2018]基础匹配算法练习题】


    谔谔我,写了好久,还重构了一次,主要是本人对于常数的估算出了严重的问题。

    看见最大流,肯定要先搞个性质出来才能做(如果您暴力见图跑网络流还能AC,您就差不多世界闻名了qwq)

    我看完题30秒大概看出来这样一个东西(以下默认从B往A连边):大权值的点能连的点小权值一定也连了,小权值的点能连的点大权值不一定连,所以让小权值去连权值尽量大的点

    这个贪心显然没毛病,而且挺好用的qwq

    一、复杂度正确并且很好想的算法

    PS:如果要看能AC的方法,那么请看“二”

    显然,找到能连并且最大的点就是前驱,搞个平衡树。

    另外,如果区间缩短,放出来的那些权值貌似不是很好处理,但是伸长的时候可以找到最大的没用过的,更新答案,所以回滚一下。

    具体实现:

    • (sqrt{m}) 次把 (a) 插入一颗初始空的平衡树
    • 区间伸长的时候找到平衡树里最大的没用过的,如果找到,那么从平衡树里删除,(++ans)
    • 扩展左端点的时候搞个数组(或 (vector)) 记录删去了哪些节点,回滚时插回去

    复杂度:

    插入节点 (sqrt{m}cdot n log n) ,左右端点扩展并找前驱更新答案 (sqrt{m} cdot nlog n) ,左端点回滚最多 (sqrt{m}cdot log n) ,总复杂度 (sqrt{m}cdot nlog n)

    于是就解决了这题

    交上去会发现 (TLE50pts) 。写假了???并没有。本地极限随机数据跑了 (40s) ,不断删去函数发现了瓶颈: (sqrt{m}cdot n) 次插入花了 (20s)

    如果您还是不知道为啥TLE,我就再说的直白一点:平衡树常数上天了!!!

    代码就不放了,要的私信(或者您AC了看我的提交记录qwq,50分的都是)

    接着我重构了/dk

    二、能AC的方法

    还是原来那个结论:让小权值去连权值尽量大的点

    换一个思路,如果排了序,那么每个点能连的点是左端点为 (1) ,右端点可以二分预处理的一段区间。

    于是考虑搞一颗线段树维护区间加区间最小值。每次加入一个点就区间加一,删除则区间减一,最后查询全局最小值即可。

    注意每个节点的初始值是区间左端点,因为到这个叶子节点最多只能连这个点下标个点,然后非叶子节点取min,最终就是左端点。

    #pragma GCC optimize(3)
    #pragma GCC target("avx,sse2,sse3,sse4,mmx")
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define rint register int
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<21],*p1=buf,*p2=buf;
    inline int rd() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    	return x*f;
    }
    const int N=160000;
    const int M=60000;
    int n,m,z,q;
    int size,bel[M];
    int a[N],b[M],c[M],ans[M];
    int val[M<<2],tag[M<<2];
    struct Q {
    	int l,r,id;
    }que[M];
    bool cmp(const Q &a,const Q &b) {
    	return bel[a.l]!=bel[b.l]?bel[a.l]<bel[b.l]:bel[a.l]&1?bel[a.r]<bel[b.r]:bel[a.r]>bel[b.r];
    }
    int min(const int &a,const int &b) {return a<b?a:b;}
    int max(const int &a,const int &b) {return a>b?a:b;}
    #define lc (p<<1)
    #define rc (p<<1|1) 
    void build(int l,int r,int p) {
    	val[p]=l;
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	build(l,mid,lc),build(mid+1,r,rc);
    }
    void pushdown(int p,int l,int r) {
    	if(!tag[p])return;
    	tag[lc]+=tag[p];
    	val[lc]+=tag[p];
    	tag[rc]+=tag[p];
    	val[rc]+=tag[p];
    	tag[p]=0;
    }
    void update(int ql,int qr,int l,int r,int p,int k) {
    	if(ql<=l&&r<=qr) {
    		tag[p]+=k,val[p]+=k;
    		return;
    	}
    	pushdown(p,l,r);
    	int mid=(l+r)>>1;
    	if(mid>=ql)update(ql,qr,l,mid,lc,k);
    	if(mid<qr)update(ql,qr,mid+1,r,rc,k);
    	val[p]=min(val[lc],val[rc]);
    }
    void add(int x) {if(c[x])update(1,c[x],1,m,1,1);}
    void pop(int x) {if(c[x])update(1,c[x],1,m,1,-1);}
    signed main() {
    	n=rd(),m=rd(),z=rd(),size=n/sqrt(m*3/2);
    	for(rint i=1;i<=n;++i)a[i]=rd();sort(a+1,a+n+1);
    	for(rint i=1;i<=m;++i)b[i]=rd();
    	for(rint i=1;i<=m;++i)c[i]=upper_bound(a+1,a+n+1,z-b[i])-a-1;
    	for(rint i=1;i<=m;++i)bel[i]=(i-1)/size+1;
    	q=rd();build(1,m,1);
    	for(rint i=1;i<=q;++i)que[i].l=rd(),que[i].r=rd(),que[i].id=i;
    	sort(que+1,que+q+1,cmp);
    	for(rint i=1,l=1,r=0;i<=q;++i) {
    		while(l<que[i].l)pop(l++);
    		while(l>que[i].l)add(--l);
    		while(r<que[i].r)add(++r);
    		while(r>que[i].r)pop(r--);
    		ans[que[i].id]=val[1]-1;
    	}
    	for(rint i=1;i<=q;++i)printf("%d
    ",ans[i]);
    	return 0;
    }
    
    路漫漫其修远兮,吾将上下而求索
  • 相关阅读:
    关于如何触发控件的事件
    MaxScript转换图像格式
    MaxScript装B技巧一则
    MaxScript.Net接收本地端口的消息执行
    MaxScript创建十二面体的代码
    MaxScript中GW使用范例一则
    Max里,Mesh真是高级自由度啊
    显示当前秒数的MaxScript
    Max2010的activex以及.net界面乱码解决方式
    半夜失眠,码点关于技术美术的字
  • 原文地址:https://www.cnblogs.com/zzctommy/p/12918510.html
Copyright © 2020-2023  润新知