20210805 noip31

考场

没有一眼题

T1 想到先贪心地算出最大得分,任意构造出一种方案,不断调整以增大字典序。
T2 发现在 \(x_k\) 确定的情况下操作次数就是左右两边的逆序对数,\(x_i\) 互不相同时直接找到最大值,枚举它最终的位置,BIT 动态维护逆序对。若有相同则最大的 \(x_i\) 最终的位置没有交集,并集为 \(n\),感觉非常对。
T3 没多想

T1 一开始以为每个位置只会换成一个它后面的更大的 \(a\),那么就可以以 \(b\) 为下标,\(a\) 为值建线段树,在保证得分最大的情况下贪心的换,拍了拍开始调,然后就降智了。。。最后分 \(4\) 类,写两颗线段树,并且还是假的。加了个卡时,9.40 才丢开
直接写 T3 暴力,以为“彩灯能够覆盖的区间两两之间只有包含和不相交的关系”是对选出区间的要求(其实是给出区间的性质),于是只能 \(O(2^mm^2)\)
T2 没 rush 完,交了个过不了样例的程序

res

rk22 20+0+0
只有用来拍 T1 的暴力有分。。。
T3 全 T 了

rk1 yzf 20+100+45
rk3 ycx 20+30+45
rk6 ys 10+10+45
rk9 wcr 20+30+0
rk13 lrx 20+20+0
rk18 zjj 10+20+0
rk22 mtr 20+0+0

总结

我记得和 hkh 说过,考场写 DS 就要做好调不出来爆 \(0\) 的准备,今天就应验了。。。

在其他两道题一分没有的情况下肝一道题超过 2h 无论如何都是极其错误的决策

如果决定要莽数据结构,那就先把其他两题的暴力写完,至少不会死的太难看
对于正确性,我大部分都是靠感觉。有一句话是一个正确的算法每个细节都是值得推敲的,如果自己都含糊不清,想的是写出来再 gdb,那不是会浪费很多时间就是做法假了。开始敲之前想清楚每个细节,尝试 hack 一会或证明正确性,复杂的 DS/DP 在纸上列好。

sol

没时间写了。。。

T1

\(O(n\log^2n)\)

char buf[1<<24],*p1=buf,*p2=buf,pbuf[1<<24],*pp=pbuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<22,stdin),p1==p2)?EOF:*p1++)
#define iocl() fwrite(pbuf,1,pp-pbuf,stdout),pp=pbuf,0
#define putchar(x) pp-pbuf==1<<22&&(iocl()),*pp++=x
int read(){
	int x=0;char c=getchar();
	while(!isdigit(c))c=getchar();
	for(;isdigit(c);c=getchar())x=x*10+c-48;
	return x;
}
void write(int x) {
	static int s[11];int l=0;
	for(;x;x/=10)s[l++]=x%10;while(l)putchar(s[--l]|48);
	putchar(' ')
}

const int N = 2e5+5;
int n,b[N],a[N];

int ans,mn,mx,cnt[N],cntb[N];

int tn;
struct Node { int l,r,a,b,s; } t[N*8];
void up(int u) {
	int ls = u<<1, rs = ls|1;
	int s = min(t[ls].b,t[rs].a);
	t[u].s = t[ls].s + t[rs].s + s;
	t[u].a = t[ls].a + t[rs].a - s;
	t[u].b = t[ls].b + t[rs].b - s;
}
void build() {
	int n = max(*max_element(b+1,b+::n+1),mx);
	tn = 1 << int(log2(n+1)+2);
	For(i,1,n) t[tn+i].a = cnt[i], t[tn+i].b = cntb[i];
	rFor(i,tn-1,1) up(i);
}
void modify(int p,int x,int y) {
	t[ p+=tn ].a += x, t[p].b += y;
	while( p >>= 1 ) up(p);
}

signed main() {
	n=read();
	For(i,1,n) b[i]=read(), ++cntb[b[i]];
	For(i,1,n) a[i]=read(), ++cnt[a[i]];
	mn = *min_element(a+1,a+n+1), mx = *max_element(a+1,a+n+1);
	build();
	ans = t[1].s;
	For(i,1,n) {
		modify(b[i],0,-1);
		int l = max(mn,b[i]+1), r = mx;
		while( l < r ) {
			int mid = l+r+1>>1;
			modify(mid,-1,0);
			if( 1+t[1].s == ans ) l = mid;
			else r = mid-1;
			modify(mid,1,0);
		}
		modify(l,-1,0);
		if( l <= r && 1+t[1].s == ans ) --ans;
		else {
			modify(l,1,0);
			l = mn, r = min(mx,b[i]);
			while( l < r ) {
				int mid = l+r+1>>1;
				modify(mid,-1,0);
				if( t[1].s == ans ) l = mid;
				else r = mid-1;
				modify(mid,1,0);
			}
			modify(l,-1,0);
		}
		--cnt[l];
		while( mn <= mx && !cnt[mx] ) --mx;
		while( mn <= mx && !cnt[mn] ) ++mn;
		write(l);
	}
	return iocl();
}

还有线段树二分的 \(O(n\log n)\) 做法 by 沈子舜

#include<bits/stdc++.h>
using namespace std;
#define uu unsigned
#define scanf abc=scanf
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define forg(i,x) for(int i=fir[x];i;i=nxt[i])
int abc;
typedef pair<int,int>pii;
typedef long long ll;
typedef uu long long ull;
typedef vector<int>VI;
inline int rd(int l,int r){return rand()%(r-l+1)+l;}

const int mxn=1e5+3,S=mxn;
int n,a[mxn],b[mxn],px[mxn],ans[mxn];
int d[mxn],m,ind[mxn],M;
int grk(int x){return upper_bound(a+1,a+n+1,x)-a;}
bool cmp1(int x,int y){return b[x]<b[y];}
set<pii>st;
void wk1(){
    for(int i=1;i<=n;++i)px[i]=i;sort(px+1,px+n+1,cmp1);
    int p=0;
    while(m<n){
        int h=px[m+1];
        p=max(p+1,grk(b[h]));
        if(p<=n)d[++m]=h,ind[h]=m;
        else return;
    }
}
struct lks{
    int a[mxn];
    void del(int x){for(;x;x-=x&-x)--a[x];}
    void add(int x){for(;x;x-=x&-x)++a[x];}
    int ask(int x){++x;int r=0;for(;x<=S;x+=x&-x)r+=a[x];return r;}
}a1;
#define mid ((l+r)>>1)
struct sdx{
    int mn[mxn*4],tg[mxn*4];
    void bu(int x=1,int l=1,int r=M){
        if(l==r)return mn[x]=a1.ask(b[d[l]])-(m-l+1),void();        bu(x*2,l,mid),bu(x*2+1,mid+1,r),up(x);
    }
    void add(int lc,int rc,int v,int x=1,int l=1,int r=M){
        assert(lc<=rc);
        if(lc<=l&&r<=rc)return put(x,v);
        down(x);if(lc<=mid)add(lc,rc,v,x*2,l,mid);if(rc>mid)add(lc,rc,v,x*2+1,mid+1,r);
        up(x);
    }
    int ask(int k,int x=1,int l=1,int r=M){if(l==r)return mn[x];down(x);return k<=mid?ask(k,x*2,l,mid):ask(k,x*2+1,mid+1,r);}
    void down(int x){if(tg[x])put(x*2,tg[x]),put(x*2+1,tg[x]),tg[x]=0;}
    void put(int x,int v){mn[x]+=v,tg[x]+=v;}
    void inf(int k,int x=1,int l=1,int r=M){
        if(l==r)return mn[x]=1e9,void();
        down(x);
        if(k<=mid)inf(k,x*2,l,mid);else inf(k,x*2+1,mid+1,r);up(x);
    }
    void up(int x){mn[x]=min(mn[x*2],mn[x*2+1]);}
    int ask0(int x=1,int l=1,int r=M){
        assert(mn[x]>=0);
        if(l==r)return mn[x]==0?l:l+1;
        down(x);
        if(mn[x*2]>0)return ask0(x*2+1,mid+1,r);else return ask0(x*2,l,mid);
    }
}se;
#undef mid
bool chk1(int k){
    if(ind[k])return 1;
    return a1.ask(b[k]);
}
int lowr(int x){int l=0,r=m,md;while(l<r){md=(l+r+1)>>1;if(b[d[md]]<x)l=md;else r=md-1;}return l;}
int main(){
    scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d",b+i);for(int i=1;i<=n;++i)scanf("%d",a+i);sort(a+1,a+n+1);
    wk1();for(int i=1;i<=n;++i)a1.add(a[i]);M=m;se.bu();for(int i=1;i<=n;++i)st.insert(pii(a[i],i));
    for(int t=1;t<=n;++t){
        if(m)assert(ind[d[m]]);
//        int mm=0;for(int i=1;i<=m;++i)mm+=ind[d[i]]!=0;    cout<<t<<"!\n";cout<<m<<' '<<mm<<endl;        for(int i=1,j=0;i<=m;++i)if(ind[d[i]])++j,printf("%d %d ",i,j),cout<<se.ask(i)<<' '<<endl,assert(se.ask(i)==a1.ask(b[d[i]])-(mm-j+1));
        if(!m){auto it=--st.end();int k=it->second;ans[t]=a[k],st.erase(pii(a[k],k));continue;}
        bool bb=chk1(t);
        if(bb){
            if(ind[t])se.add(ind[t],m,-1),se.inf(ind[t]),ind[t]=0;
            else{while(!ind[d[m]])--m;ind[d[m]]=0,--m;}
            while(m>0&&!ind[d[m]])--m;
            if(m)se.add(1,m,1);
        }
        int rr=m?se.ask0():2;
//        for(int i=1;i<rr&&i<=m;++i)assert(se.ask(i)>0);assert(rr>m||se.ask(rr)==0);
        rr=rr>m?2e5:b[d[rr]];
        if(!bb)rr=min(rr,b[t]);
        auto it=--st.lower_bound(pii(rr,1e9));
        int k=it->second;
        ans[t]=a[k],st.erase(pii(a[k],k)),a1.del(a[k]);
        int pp=lowr(ans[t]);
        if(pp)se.add(1,pp,-1);
    }
    for(int i=1;i<=n;++i)printf("%d ",ans[i]);puts("");
    return 0;
}

T2
const int N = 1e5+5;
int n,b[N];

int a[N];
LL ans;

#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
struct Node{ int sum; PII mn; } t[N*4];
void up(int u) {
	t[u].mn.fi = a[t[ls].mn.fi] <= a[t[rs].mn.fi] ? t[ls].mn.fi : t[rs].mn.fi;
	t[u].mn.se = a[t[ls].mn.se] < a[t[rs].mn.se] ? t[ls].mn.se : t[rs].mn.se;
	t[u].sum = t[ls].sum + t[rs].sum;
}
void build(int u,int l,int r) {
	if( l == r ) { t[u] = {1,MP(l,l)}; return; }
	build(ls,l,mid), build(rs,mid+1,r);
	up(u);
}
void erase(int u,int l,int r,int p) {
	if( l == r ) { t[u] = {0,MP(0,0)}; return; }
	if( p <= mid ) erase(ls,l,mid,p);
	else erase(rs,mid+1,r,p);
	up(u);
}
int query(int u,int l,int r,int ql,int qr) {
	if( ql > qr ) return 0;
	if( ql <= l && r <= qr ) return t[u].sum;
	int res = 0;
	if( ql <= mid ) res = query(ls,l,mid,ql,qr);
	if( mid < qr ) res += query(rs,mid+1,r,ql,qr);
	return res;
}

signed main() {
	read(n);
	a[0] = 0x3f3f3f3f;
	For(i,1,n) read(a[i]);
	build(1,1,n);
	For(i,1,n) {
		PII u = t[1].mn;
		int sl = query(1,1,n,1,u.fi-1), sr = query(1,1,n,u.se+1,n);
		ans += min(sl,sr);
		erase(1,1,n,sl<sr?u.fi:u.se);
	}
	write(ans);
	return iocl();
}
T3
const int N = 6e5+5;
int n,m;
struct Node { int l,r,val; } a[N];
bool operator < (const Node &x,const Node &y)
	{ return x.r-x.l!=y.r-y.l ? x.r-x.l>y.r-y.l : mt()&1; }

int fa[N],h[N];
LL ans;
vector<int> to[N];
priority_queue<LL> tmp,pq[N];

#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
namespace seg {
int t[N*4];
void down(int u) { if( ~t[u] ) t[ls] = t[rs] = t[u], t[u] = -1; }
void modify(int u,int l,int r,int ql,int qr,int x) {
	if( ql <= l && r <= qr ) { t[u] = x; return; }
	down(u);
	if( ql <= mid ) modify(ls,l,mid,ql,qr,x);
	if( mid < qr ) modify(rs,mid+1,r,ql,qr,x);
}
int query(int u,int l,int r,int p) {
	if( l == r ) return t[u];
	down(u);
	return p<=mid ? query(ls,l,mid,p) : query(rs,mid+1,r,p);
}
}
#undef ls
#undef rs
#undef mid

void dfs(int u) {
	for(int v : to[u]) dfs(v), ckmax(h[u],h[v]);
	for(int &v : to[u]) if( h[v] == h[u] ) {
		swap(pq[v],pq[u]), v = -1;
		break;
	}
	++h[u];
	for(int v : to[u]) if( ~v ) {
		while( !pq[v].empty() )
			tmp.push(pq[u].top()+pq[v].top()),
			pq[u].pop(), pq[v].pop();
		swap(pq[u],tmp);
		while( !tmp.empty() ) pq[u].push(tmp.top()), tmp.pop();
	}
	pq[u].push(a[u].val);
}

signed main() {
	read(n,m);
	For(i,1,m) read(a[i].l,a[i].r,a[i].val);
	sort(a+1,a+m+1);
	// For(i,1,m) rFor(j,i-1,1) if( a[j].l <= a[i].l && a[i].r <= a[j].r )
	// 	{ fa[i] = j; break; }
	// For(i,1,m) to[fa[i]].pb(i);
	For(i,1,m) {
		fa[i] = seg::query(1,1,n,a[i].l), to[fa[i]].pb(i);
		seg::modify(1,1,n,a[i].l,a[i].r,i);
	}
	dfs(0);
	For(i,1,m) {
		pq[0].push(0);
		ans += pq[0].top(), pq[0].pop();
		write(ans,' ');
	}
	return iocl();
}
posted @ 2021-08-05 19:37  401rk8  阅读(59)  评论(1编辑  收藏  举报