답안 #209341

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
209341 2020-03-13T20:42:48 Z Segtree 가로등 (APIO19_street_lamps) C++14
0 / 100
5000 ms 187896 KB
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
typedef unordered_set<ll> uset;
#define rep(i,n) for(int i=0;i<n;i++)
#define rrep(i,n) for(int i=0;i<=n;i++)
#define chmin(a,b) a=min(a,b)
#define chmax(a,b) a=max(a,b)
#define lo(x,y) lower_bound(x.begin(),x.end(),y)-x.begin()
#define all(x) x.begin(),x.end()
#pragma gcc optimize("O3")
#pragma gcc optimize("unroll-loops")
#pragma gcc target("avx2,see4")
#define N (1<<19)
ll q,typ[N],L[N],R[N],S[N],T[N],VAL[N];
typedef struct segtree2D{
	typedef struct segtree{//区間加算、区間和
		ll *dat,*laz,*wid;
		ll n;
		void init(vector<ll> values){//values[i+1]-values[i]の長さのものが|values|-1個並んでる
			n=values.size();//配列外参照を防ぐため+1
			dat=new ll[2*n];
			laz=new ll[2*n];
			wid=new ll[2*n];
			rep(i,2*n)dat[i]=laz[i]=wid[i]=0;
			for(int i=0;i<n-1;i++)wid[i+n]=values[i+1]-values[i];
			for(int i=n-1;i>0;i--)wid[i]=wid[i*2]+wid[i*2+1];
		}
		ll eval(ll k){
			if(k<n){
				laz[k*2]+=laz[k];
				laz[k*2+1]+=laz[k];
			}
			dat[k]+=laz[k]*wid[k],laz[k]=0;
			return dat[k];
		}
		void add(ll l,ll r,ll val){//[l,r),非再起注意
			l+=n,r+=n;
			for(ll a=l,b=r;a<b;a>>=1,b>>=1){
				if(a&1)laz[a++]+=val;
				if(b&1)laz[--b]+=val;
			}
			for(ll a=l,b=r;a+b;a>>=1,b>>=1){
				dat[a/2]=eval(a)+eval(a^1);
				dat[b/2]=eval(b)+eval(b^1);
			}
		}
		ll sum(ll l,ll r){//[l,r),非再起注意
			l+=n,r+=n;
			for(ll d=20;~d;d--){
				eval(l>>d);
				eval(r>>d);
			}
			ll res=0;
			for(ll a=l,b=r;a<b;a>>=1,b>>=1){
				if(a&1)res+=eval(a),a++;
				if(b&1)b--,res+=eval(b);
			}
			return res;
		}
	}segtree;
	segtree seg[2*N];
	vector<ll> values[2*N];
	vector<ll> solve(){
		rep(i,q){
			if(typ[i]==0){//[s,s]*[l,r)にvalを加算
				for(ll x=S[i]+N;x;x>>=1){
					values[x].push_back(L[i]);
					values[x].push_back(R[i]);
				}
			}
			else{//[s,t)*[l,r)の総和を求める
				for(ll a=S[i]+N,b=T[i]+N;a<b;a>>=1,b>>=1){
					if(a&1){
						values[a].push_back(L[i]);
						values[a].push_back(R[i]);
						a++;
					}
					if(b&1){
						b--;
						values[b].push_back(L[i]);
						values[b].push_back(R[i]);
					}
				}
			}
		}
		rep(i,2*N){
			sort(all(values[i]));
			seg[i].init(values[i]);
		}
		vector<ll> fans;
		rep(i,q){
			if(typ[i]==0){//[s,s]*[l,r)にvalを加算
				for(ll x=S[i]+N;x;x>>=1){
					ll LL=lo(values[x],L[i]);
					ll RR=lo(values[x],R[i]);
					seg[x].add(LL,RR,VAL[i]);
				}
			}
			else{//[s,t)*[l,r)の総和を求める
				ll res=0;
				for(ll a=S[i]+N,b=T[i]+N;a<b;a>>=1,b>>=1){
					if(a&1){
						ll LL=lo(values[a],L[i]);
						ll RR=lo(values[a],R[i]);
						res+=seg[a].sum(LL,RR);
						a++;
					}
					if(b&1){
						b--;
						ll LL=lo(values[b],L[i]);
						ll RR=lo(values[b],R[i]);
						res+=seg[b].sum(LL,RR);
					}
				}
				fans.push_back(res);
			}
		}
		return fans;
	}
}segtree2D;
segtree2D seg;

void register_upd(ll t,ll l,ll r,ll val){
	typ[q]=0,L[q]=l,R[q]=r,S[q]=t,T[q]=-1,VAL[q]=val;
	q++;
}
vector<ll> querysid;
void register_sum(ll s,ll t,ll l,ll r,ll id){
	typ[q]=1,L[q]=l,R[q]=r,S[q]=s,T[q]=t;
	querysid.push_back(id);
	q++;
}

typedef struct rng{//[l,r)では[t,t]*[l,r)が1になっている、
	ll l,r,t;
	bool operator<(const rng&key)const{
		return this->l<key.l;
	}
}rng;
set<rng> rngs;//rngの集合、1→nの方向に走査する
void EXAM1(){
	ll res=0;
	for(auto e:rngs)res+=e.r-e.l;
	cerr<<"EXAM:"<<res<<endl;
}
int main(){
	ll n,m;
	string s;
	cin>>n>>m>>s;
	vector<P> zerorng[N];//zerorng[i]:=ランプiが消えている区間[fi,sc)の集合
	vector<P> querys[N];//querys[b]:=右端がbで、a=fiで、id=scのクエリの集合
	{//zerorngとquerysを求める
		ll mas[N];//mas[i]:=ランプiが最後に消されたときの時間、現在光っている時は不要
		for(int i=1;i<=n;i++)if(s[i-1]=='0')mas[i]=0;
		rep(i,m){
			string com;
			cin>>com;
			if(com=="toggle"){
				ll x; cin>>x;
				if(s[x-1]=='0'){
					zerorng[x].push_back(make_pair(mas[x],i+1));
					s[x-1]='1';
				}
				else s[x-1]='0',mas[x]=i;
			}
			if(com=="query"){
				ll a,b; cin>>a>>b;
				querys[b-1].push_back(make_pair(a,i));
			}
		}
		for(int i=1;i<=n;i++){
			if(s[i-1]=='0'){
				zerorng[i].push_back(make_pair(mas[i],m));
			}
		}
	}
	q=0;
	rngs.insert((rng){0,m,0});
	register_upd(0,0,m,+1);
	EXAM1();
	for(int i=1;i<=n;i++){
		for(auto p:zerorng[i]){//ランプが消えている区間のところで、2DSegtreeを更新する。添字がずれている可能性あり
			rng x=(rng){p.first,p.second,i};
			{//元々あったrngを消して、更新クエリを2Dsegtreeに投げる
				auto it=rngs.lower_bound(x);
				while(it!=rngs.end()&&it->l<p.second){
					if(it->r<=p.second){//[p.fi,p.sc)に完全に含まれている
						register_upd(it->t,it->l,it->r,-1);
						it=rngs.erase(it);
					}
					else{//p.fi<=it->l<p.second<it->r
						register_upd(it->t,it->l,p.second,-1);
						rng news=(rng){p.second,it->r,it->t};
						rngs.erase(it);
						rngs.insert(news);
						break;
					}
				}
				it=rngs.lower_bound(x);
				if(it!=rngs.begin()){
					it--;
					if(it->l<=p.first&&p.second<=it->r){//元々あったものの中に、追加するものを完全に含んでいるものがあった
						register_upd(it->t,p.first,p.second,-1);
						rngs.erase(it);
					}
					else{//左側で重なっているもの
						register_upd(it->t,p.first,it->r,-1);
						rng news=(rng){it->l,p.first,it->t};
						rngs.erase(it);
						rngs.insert(news);
					}
				}
			}
			{//新しいrngをいれて、更新クエリを2DSegtreeに投げる
				cerr<<"upd:"<<p.first<<" "<<p.second<<" "<<i<<endl;
				rngs.insert((rng){p.first,p.second,i});
				register_upd(i,p.first,p.second,+1);
			}
			EXAM1();
		}
		for(auto p:querys[i]){//取得クエリを2DSegtreeに投げる
			cerr<<"sum:"<<p.first<<" "<<0<<" "<<p.second+1<<" "<<p.second<<endl;
			register_sum(p.first,N-1,0,p.second+1,p.second);
		}
	}
	vector<ll> fans=seg.solve();
	vector<P> ans;
	for(int i=0;i<fans.size();i++){
		ans.push_back(make_pair(querysid[i],fans[i]));
	}
	sort(all(ans));
	for(auto t:ans)cout<<t.first+1-t.second<<"\n";
}

Compilation message

street_lamps.cpp:17:0: warning: ignoring #pragma gcc optimize [-Wunknown-pragmas]
 #pragma gcc optimize("O3")
 
street_lamps.cpp:18:0: warning: ignoring #pragma gcc optimize [-Wunknown-pragmas]
 #pragma gcc optimize("unroll-loops")
 
street_lamps.cpp:19:0: warning: ignoring #pragma gcc target [-Wunknown-pragmas]
 #pragma gcc target("avx2,see4")
 
street_lamps.cpp: In function 'int main()':
street_lamps.cpp:235:15: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  for(int i=0;i<fans.size();i++){
              ~^~~~~~~~~~~~
# 결과 실행 시간 메모리 Grader output
1 Incorrect 184 ms 181112 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 5072 ms 77272 KB Time limit exceeded
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 226 ms 187896 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 220 ms 186872 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 184 ms 181112 KB Output isn't correct
2 Halted 0 ms 0 KB -