1. 程式人生 > 其它 >『P1177』與『P2572』聯合題解

『P1177』與『P2572』聯合題解

P1177

基數排序

基本理論就是把一個數字分成k個關鍵字,每次對n個數同時對於k關鍵字排序

時間複雜度\(O(n \times \frac{n_max}{radix})\),空間複雜度是\(O(n+radix)\)

radix為取的基數,通常取 \(65536\) 或者是 \(256\)

\(NOI\)\(NOIp\) 的配置大概取 \(256\) 為基數能卡進 \(L1\) 快取記憶體,但是你取 \(65536\) 在聯賽裡就卡不進 \(L1\) 記憶體訪問不連續就會非常慢……(但是luogu評測姬 \(L1\) 似乎大得離譜

#include <bits/stdc++.h>

using namespace std;

#define INF 1<<30
#define int long long 
#define pb push_back
%:define ill unsigned long long 
%:define lowbit(x) (x&(-x))
%:define Int unsigned int 
#define pii pair<int,int>

template<typename _T>
inline void read(_T &x)
{
	x = 0;int f= 1;char s = getchar();
	while(s<'0'||s>'9'){f=1;if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	x*=f;
}

const int U = 256;
const int BIT = 8;

const int np = 1e5 + 5;

int n;
int a[np];
int b[np];
int bac[np];

inline int Get(int x,int d)
{
	return (x >> BIT * d) & (U - 1);
}

inline void sort_()
{
	for(int d=0;d<4;d++)
	{
		for(int i=0;i<U;i++) bac[i] = 0;
		for(int i=1;i<=n;i++) bac[Get(a[i],d)]++;
		for(int i=0;i<U;i++) bac[i] += bac[i-1];
		for(int i=n;i>=1;i--) b[bac[Get(a[i],d)]--] = a[i];
		for(int i=1;i<=n;i++) a[i] = b[i];
	}
}

signed main()
{
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	
	sort_();
	
	for(int i=1;i<=n;i++)
	cout<<a[i]<<" ";
}

P2572

裸的資料結構題,題目已經明示線段樹維護。

(一開始我還想敲一個珂朵莉苟過去,但直接被卡成\(30pts\)

難點在於懶標記的維護與下放,對於懶標記問題

思考問題的時候需要牢牢把握一下幾點:

懶標記本質是對自己兒子修改的訊號
需要思考懶標記之間的優先順序關係
需要思考下放懶標記時對子節點懶標記的影響

這樣來思考問題解決懶標記還是蠻輕鬆的

(把這篇整上來只是想記錄一下這種方法,而不是就題論題

#include <bits/stdc++.h>

using namespace std;

#define INF 1<<30
#define int long long 
#define pb push_back
%:define ill unsigned long long 
%:define lowbit(x) (x&(-x))
%:define Int unsigned int 

template<typename _T>
inline void read(_T &x)
{
	x = 0;int f= 1;char s = getchar();
	while(s<'0'||s>'9'){f=1;if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	x*=f;
}

const int np = 1e5 + 5;

struct node{
	int l,r;
	int sum;
	int lmax[2],rmax[2],maxn_len[2];
	int cov[2];
	int typ_f;
	node *ls,*rs;
	
	inline bool inrange(int L,int R){return L<=l&&r<=R;}
	inline bool outofrange(int L,int R){return r < L||R < l;}
	
	inline void pushup()
	{
		sum = ls->sum + rs->sum;
		for(int i=0;i<=1;i++)
		{
			maxn_len[i] = ls->rmax[i] + rs->lmax[i];
			maxn_len[i] = max(maxn_len[i] , ls->maxn_len[i]);
			maxn_len[i] = max(maxn_len[i] , rs->maxn_len[i]);
			if(ls->lmax[i] == ls->r - ls->l + 1 )lmax[i] = ls->lmax[i] + rs->lmax[i];
			else lmax[i] = ls->lmax[i];
			if(rs->rmax[i] == rs->r - rs->l + 1)rmax[i] = rs->rmax[i] + ls->rmax[i];
			else rmax[i] = rs->rmax[i];			
		}
	}
	
	inline void pushdown()
	{
		if(cov[1])
		{
			ls->maketag(1);
			rs->maketag(1);
			cov[1] = 0;
		 } 
		if(cov[0])
		{
			ls->maketag(0);
			rs->maketag(0);
			cov[0] = 0;
		 } 
		if(typ_f) ls->make_f() , rs->make_f(),typ_f^=1;
	}
	
	inline void make_f()
	{
		sum = (r - l + 1) - sum;
		swap(lmax[1],lmax[0]);
		swap(rmax[1],rmax[0]);
		swap(maxn_len[1],maxn_len[0]);
		typ_f ^= 1;
	}
		
	inline void maketag(int vl)
	{
		sum = (r - l + 1) * vl;
		lmax[vl] = r - l + 1 , lmax[!vl] = 0;
		rmax[vl] = r - l + 1 , rmax[!vl] = 0;
		maxn_len[vl] = r-l + 1,maxn_len[!vl] = 0;
		cov[vl] = 1;cov[!vl] = typ_f = 0;
	}
	
	inline int query_opt_3(int L,int R)
	{
		if(inrange(L,R))
		{
			return sum;
		}
		else
		{	
			if(!outofrange(L,R))
			{
				pushdown();
				return ls->query_opt_3(L,R) + rs->query_opt_3(L,R);
			 } 
			else return 0;
		}
	}
	
	inline int query_opt_4(int L,int R)
	{
		if(inrange(L,R))
		{
			return maxn_len[1];
		}
		else
		{
			if(!outofrange(L,R))
			{
				pushdown();
				int mid = l + r >> 1; 
				int x = 0;
				
				if( L<= mid && mid<=R && L<=mid + 1 && mid + 1<=R && ls->rmax[1] && rs->lmax[1])
				{
					if(mid + rs->lmax[1] <= R) x+= rs->lmax[1];
					else x += R-(mid + 1) + 1;
					if(L <= mid - ls->rmax[1] + 1) x += ls->rmax[1];
					else x += mid - L + 1; 
				}
				return max({x ,ls->query_opt_4(L,R) , rs->query_opt_4(L,R) });
			} 
			else return 0;
		}
	}
	
	inline void cover(int L,int R,int vl)
	{
		if(inrange(L,R))
		{
			maketag(vl);
			return ;
		}
		else
		{
			if(!outofrange(L,R))
			{
				pushdown();
				ls->cover(L,R,vl);
				rs->cover(L,R,vl);
				pushup();
			}
		}
	}
	
	inline void qf(int L,int R)
	{
		if(inrange(L,R))
		{
			make_f();
			return;
		}
		else
		{
			if(!outofrange(L,R))
			{
				pushdown();
				ls->qf(L,R);
				rs->qf(L,R);
				pushup();
			}
		}
	}
	
}mem[np * 2 + 10] , *pool = mem;
int a[np];
inline node *New(){return ++pool;}

inline node *build(int L,int R)
{
	node *u = New();
	u->l = L;
	u->r = R;
	if(L == R)
	{
		u->ls = u->rs = NULL;
		if(a[L]) u->sum = u->maxn_len[1] = u->lmax[1] = u->rmax[1] = 1;
		else u->maxn_len[0] = u->lmax[0] = u->rmax[0] = 1;
	}
	else 
	{
		int mid = L+R>>1;
		u->ls = build(L,mid);
		u->rs = build(mid + 1,R);
		u->pushup();
	}
	return u;
}
node *rot;


signed main()
{
	int n,m;
	read(n);
	read(m);
	for(int i=1;i<=n;i++)
	read(a[i]);
	
	rot = build(1,n);
	
	for(int i=1,opt,l,r;i<=m;i++)
	{
		read(opt);
		read(l);
		read(r);
		l++;
		r++;
		switch(opt)
		{
			case 0:{
				rot->cover(l,r,0);
				break;
			}
			case 1:{
				rot->cover(l,r,1);
				break;
			}
			case 2:{
				rot->qf(l,r);
				break;
			}
			case 3:{
				cout<<rot->query_opt_3(l,r)<<'\n';
				break;
			}
			case 4:{
				cout<<rot->query_opt_4(l,r)<<'\n';
				break;
			}
		}
	}
	return 0;
}

至於為什麼是聯合題解

因為兩個題的字數加起來不是很多,分開寫有點浪費而已

\(End\)