zoukankan      html  css  js  c++  java
  • 2021.09.23模拟赛

    2021.09.23 模拟赛

    下午,受困于 AC自动机 的深潭中时,得知要参加模拟赛。

    下午还是脑子迷乱,状态不太好……

    赛时

    开场看题,注意到 -O2 -std=c++14.

    粗略扫了一遍题:

    (T_1) : 构造矩阵,求对角线和。但是优化需要数学?

    (T_2) : 乍一看是图论。注意到有加边和删边,无法用图来解决。

    (T_3) : 期望问题……不会……

    (T_4) : 是个分块吧,但是分块不是 NOI 级内容吗……?

    一圈看下来,感觉只有 (T_2)(T_4) 可做,

    先攻 (T_2) 。(用了大概 3 个小时)

    大概想到:

    从前向后连的边是无用的,直接忽略。
    从后向前的边,等价于将 ([X,Y]) 中的点变为联通。
    删掉一条边,有点不太会搞。

    但是?

    考虑从后向前的边:将 ([X,Y]) 的点变为联通,可以转化为将 ([X,Y]) 的点打上 (+1) 的标记。
    那么,删边相当于将 ([X,Y]) 内的点打上 (-1) 的标记。

    考虑联通性,即是找到包含 (X) 的标记最左端点。

    这个过程二分解决。

    但是,受困在标记最左端点这里(指卡了 3 个小时),没有想出线段树如何处理区间内有多少个 (0) 的问题。

    剩下大概半个小时,写了下 (T_4) 的线段树暴力。

    赛后

    (T_1)(T_3) 真的是纯数学……

    (T_2) 的思路就是正解思路。后来在研究下发现,只需要线段树支持区间修改、统计区间内最小值及其出现的位置即可……

    这里是思维没有打开的问题了……

    可以类比之前的扫描线问题。同样是区间 (+1,-1) ,统计区间内 (0) 的问题,因为当时没有太仔细考虑,且赛时思路没有打开,导致此题想出了正解却没有写出。

    以下是自己赛后的 AC 代码。

    #include <bits/stdc++.h>
    #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    const int INF = 0x3f3f3f3f , N = 5e5+5;
    typedef long long ll;
    typedef unsigned long long ull;
    inline ll read(){
    	ll ret = 0; char ch = ' ', c = getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar();
    	return ch == '-' ? -ret : ret;
    }
    int n,m;
    struct Segtre{int min,laz,pos;}tre[N<<2];
    inline void pushup(int k){
    	tre[k].min = min(tre[k<<1].min , tre[k<<1|1].min);
    	tre[k].pos = tre[k<<1].min < tre[k<<1|1].min ? tre[k<<1].pos : tre[k<<1|1].pos;
    }
    inline void mod(int k,int l,int r,int w){
    	tre[k].min += w,
    	tre[k].laz += w;
    }
    inline void pushdown(int k,int l,int r){
    	if(!tre[k].laz) return;
    	int mid = (l + r) >> 1;
    	mod(k<<1,l,mid,tre[k].laz),
    	mod(k<<1|1,mid+1,r,tre[k].laz);
    	tre[k].laz = 0;
    }
    void build(int k,int l,int r){
    	if(l == r){tre[k] = (Segtre){0,0,l}; return;}
    	int mid = (l + r) >> 1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	pushup(k);
    }
    void modify(int k,int l,int r,int x,int y,int w){
    	if(x <= l && r <= y) {mod(k,l,r,w); return;}
    	pushdown(k,l,r);
    	int mid = (l + r) >> 1;
    	if(x <= mid) modify(k<<1,l,mid,x,y,w);
    	if(y > mid)  modify(k<<1|1,mid+1,r,x,y,w);
    	pushup(k);
    }
    pair<int,int> query(int k,int l,int r,int x,int y){
    	if(x <= l && r <= y) return make_pair(tre[k].min,tre[k].pos);
    	pushdown(k,l,r);
    	int mid = (l + r) >> 1;
    	if(y <= mid) return query(k<<1,l,mid,x,y);
    	if(x > mid)  return query(k<<1|1,mid+1,r,x,y);
    	pair<int,int> ls = query(k<<1,l,mid,x,y), rs = query(k<<1|1,mid+1,r,x,y);
    	return make_pair(min(ls.first,rs.first), (ls.first < rs.first ? ls.second : rs.second) );
    }
    signed main(){
    //	fo("build");
    	n = read(), m = read();
    	build(1,1,n);
    	while(m--){
    		int op = read();
    		switch(op){
    			case 1:{
    				int r = read() , l = read();
    				if(l >= r) continue;
    				modify(1,1,n,l,r,1);
    				break;
    			}
    			case 2:{
    				int r = read() , l = read();
    				if(l >= r) continue;
    				modify(1,1,n,l,r,-1);
    				break;
    			}
    			default:{
    				int x = read();
    				pair<int,int> ck = query(1,1,n,1,x);
    				if(ck.first) printf("%d
    ",n);
    				else if(ck.second < x) printf("%d
    ",n-ck.second);
    				else printf("%d
    ",n-x+1);
    				break;
    			}
    		}
    	}
    	return 0;
    }
    

    关于 (T_4),确实是个分块。这里就因为时间较紧,先着重研究提高级内容了。

    正解就是,按 (sqrt N) 分块,(kge sqrt N) 的就暴力修改,最后处理一下所有 (k<sqrt N) 的,更新答案。

  • 相关阅读:
    CF 461B Appleman and Tree
    POJ 1821 Fence
    NOIP 2012 开车旅行
    CF 494B Obsessive String
    BZOJ2337 XOR和路径
    CF 24D Broken robot
    POJ 1952 BUY LOW, BUY LOWER
    SPOJ NAPTIME Naptime
    POJ 3585
    CF 453B Little Pony and Harmony Chest
  • 原文地址:https://www.cnblogs.com/Shinomiya/p/15329212.html
Copyright © 2011-2022 走看看