zoukankan      html  css  js  c++  java
  • 题解 P5445 [APIO2019]路灯

    view in Push_Y's blog

    思路

    对于一段连续的能够互相到达的站点,这里不妨称它为一个连通块

    考虑用线段树维护每一个连通块

    对于一个连通块里的每一个站点,存下这个连通块的左右端点(即一个站点所能到达的最左端和最右端)

    对于一次连通块改变的操作,以操作的时刻 (t) 来记录对答案产生的贡献

    • 若为插入操作,对修改的区间贡献为 (-t)

    • 若为删除操作,对修改的区间贡献为 (t)

    特别的:询问时刻如果两点是连通的,记录答案 (+t)

    这样处理可以很方便的解决某两点连通的时长

    考虑切换第 (k) 个路灯的状态对 (k)(k+1) 所在连通块的影响

    • (k) 个路灯原先是亮的

      • 相当于把这个连通块以 (k)(k+1) 之间为断点分成 2 个连通块

      • 具体的,在线段树中查询得到左右端点 (l)(r),修改 ([l,k])([k+1,r]) 分别为 1 个连通块

    • (k) 个路灯原先是灭的

      • 相当于是将 (k)(k+1) 所在的 2 个连通块合并成 1 个

      • 具体的,查询 (k) 所能到达的左端点和 (k+1) 所能到达的右端点,记为 (l)(r),修改 ([l,r]) 为 1 个连通块

    每次操作的贡献的区间修改,可以转化为二维平面上的矩形加,于是可以用容斥的思想在矩形上差分

    比如对于 ([l,k])([k+1,r]) 这两个区间的一次插入操作,看做是插入 ([l,k+1]、[k,r]) 并删除 ([l,r]、[k,k+1])

    二维的矩形加上时间这一维 => 三维数点问题
    这里我用 CDQ分治 实现
    由于码力太弱,在题解和 阿丑 神佬的帮助下完成

    CODE

    //#pragma GCC optimize("Ofast") 
    #include <bits/stdc++.h>
    #define int long long
    #define ls x<<1
    #define rs x<<1|1
    using namespace std;
    typedef pair<int,int> pi;
    
    inline int gin(){
    	char c=getchar();
    	int s=0,f=1;
    	while(c<'0' || c>'9'){
    		if(c=='-')f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		s=(s<<3)+(s<<1)+(c^48);
    		c=getchar();
    	}
    	return s*f;
    }
    
    const int N=6e5+5;
    char s[N];
    int n,Q,tot,c[N],a[N],ans[N];
    bool vis[N];
    
    struct seg{
    	pi py;
    	bool tag;
    } tr[N<<2];
    
    struct node{
    	int op,x,y1,y2,id,v;
    } t[N],tmp[N];
    
    void pushdown(int x){
    	if(tr[x].tag){
    		tr[ls].py=tr[rs].py=tr[x].py;
    		tr[ls].tag=tr[rs].tag=1;
    		tr[x].tag=0;
    	}
    }
    
    void build(int x,int l,int r){
    	if(l==r){
    		tr[x].py=make_pair(l,l);
    		return;
    	}
    	int mid=l+r>>1;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    }
    
    void change(int x,int l,int r,int L,int R,pi d){
    	if(L<=l && r<=R){
    		tr[x].py=d;
    		tr[x].tag=1;
    		return;
    	}
    	pushdown(x);
    	int mid=l+r>>1;
    	if(L<=mid) change(ls,l,mid,L,R,d);
    	if(mid< R) change(rs,mid+1,r,L,R,d);
    }
    
    pi query(int x,int l,int r,int p){
    	if(l==r) return tr[x].py;
    	pushdown(x);
    	int mid=l+r>>1;
    	if(p<=mid) return query(ls,l,mid,p);
    	else return query(rs,mid+1,r,p);
    }
    
    void upd(int x,int d){
    	while(x<=n+1){
    		c[x]+=d;
    		x+=x&-x;
    	}
    }
    void del(int x){
    	while(x<=n+1){
    		if(c[x]) c[x]=0;
    		else break;
    		x+=x&-x;
    	}
    }
    int ask(int x){
    	int res=0;
    	while(x){
    		res+=c[x];
    		x-=x&-x;
    	}
    	return res;
    }
    
    void cdq(int l,int r) {
    	if(l==r) return;
    	int mid=l+r>>1,p=l,q=mid+1;
    	cdq(l,mid),cdq(mid+1,r);
    	for(int i=l;i<=r;i++){
    		if(q>r || p<=mid && t[p].x<=t[q].x){
    			tmp[i]=t[p++];
    			if(tmp[i].op==2) continue;
    			upd(tmp[i].y1,tmp[i].v);
    			upd(tmp[i].y2+1,-tmp[i].v);
    		}
    		else {
    			tmp[i]=t[q++];
    			if(tmp[i].op==2) ans[tmp[i].id]+=ask(tmp[i].y1);
    		}
    	}
    	for(int i=l;i<=r;i++){
    		t[i]=tmp[i];
    		if(t[i].op==1){
    			del(tmp[i].y1);
    			del(tmp[i].y2+1);
    		}
    	}
    	return;
    }
    
    signed main(){
    	n=gin(),Q=gin();
    	scanf("%s",s);
    	for(int i=1;i<=n;i++)
    		a[i]=s[i-1]-'0';
    	build(1,1,n+1);
    	for(int i=1;i<=n;i++)
    		if(a[i]==1 && !vis[i]){
    			int j=i;
    			vis[i]=1;
    			while(a[j]) vis[++j]=1;
    			change(1,1,n+1,i,j,make_pair(i,j));
    		}
    	memset(vis,0,sizeof(vis));
    	int tot=0;
    	for(int i=1;i<=Q;i++){
    		scanf("%s",s);
    		t[++tot].op=(s[0]=='t' ? 1 : 2);
    		t[tot].id=i;
    		if(t[tot].op==1){
    			int k=gin();
    			++tot, t[tot]=t[tot-1];
    			if(a[k]==1){
    				pi u=query(1,1,n+1,k);
    				t[tot-1].x=u.first,t[tot].x=k+1;
    				t[tot-1].y1=t[tot].y1=k+1,t[tot-1].y2=t[tot].y2=u.second;
    				t[tot-1].v=i, t[tot].v=-i;
    				change(1,1,n+1,u.first,k,make_pair(u.first,k));
    				change(1,1,n+1,k+1,u.second,make_pair(k+1,u.second));
    			}
    			else {
    				pi p1=query(1,1,n+1,k),p2=query(1,1,n+1,k+1);
    				t[tot-1].x=p1.first,t[tot].x=k+1;
    				t[tot-1].y1=t[tot].y1=k+1,t[tot-1].y2=t[tot].y2=p2.second;
    				t[tot-1].v=-i, t[tot].v=i;
    				change(1,1,n+1,p1.first,p2.second,make_pair(p1.first,p2.second));
    			}
    			a[k]^=1;
    		}
    		else {
    			t[tot].x=gin(),t[tot].y1=gin();
    			pi p=query(1,1,n+1,t[tot].x);
    			if(p.second>=t[tot].y1)
    				ans[i]+=i;
    			vis[i]=1;
    		}
    	}
    	cdq(1,tot);
    	for(int i=1;i<=Q;i++)
    		if(vis[i])
    			printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    30130413 腾讯笔试
    未来网络 SDN
    XAML实例教程系列 XAML传递参数到值转换类实例
    【转】Silverlight MVVM 贴近实战(一)
    XAML实例教程系列 依赖属性和附加属性
    Silverlight开发工具汇总
    XAML实例教程系列 类型转换器(Type Converter)
    XAML实例教程系列 标记扩展(Markup Extensions)
    XAML实例教程系列 事件(Event)
    [转]XAML实例教程系列 命名空间(NameSpace)
  • 原文地址:https://www.cnblogs.com/wzsyyh/p/ludeng.html
Copyright © 2011-2022 走看看