191024省选测试题解

T1:有n个不相交矩形障碍,求从原点走到某个目标点的最短路,目标点在x轴上
显然矩形的右端点是没用的,我们保留左边即可
显然不会往左走,dp一下是 n 2 n^2 n2的,用扫描线优化一下即可

#include
#define pb push_back
#define ll long long 
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=5e5+5,INF=1e9;
inline int D(int x1,int y1,int x2,int y2){return abs(x1-x2)+abs(y1-y2);}
int n,aim;
struct sqr{
	int lx,rx,ly,ry;
	inline bool operator < (const sqr &rhs)const{return lx<rhs.lx;}
}p[N];
struct info{
	int x,y,dis;
	info(){}
	info(int _x,int _y,int _dis):x(_x),y(_y),dis(_dis){}
	inline bool operator < (const info &rhs)const{return y<rhs.y;}
};
set<info>s;
int main(){
	n=read();aim=read();
	for(int i=1;i<=n;i++){
		int lx=read(),ly=read(),rx=read(),ry=read();
		if(lx>rx) swap(lx,rx);if(ly>ry) swap(ly,ry);
		p[i].lx=lx,p[i].rx=rx,p[i].ly=ly,p[i].ry=ry;
	}
	s.insert(info(0,0,0));
	sort(p+1,p+n+1);
	for(int i=1;i<=n;i++){
		set<info>::iterator l=s.lower_bound(info(0,p[i].ly,0));
		set<info>::iterator r=s.upper_bound(info(0,p[i].ry,0));
		int L=INF,R=INF;
		while(l!=r){
			L=min(L,l->dis+D(p[i].lx,p[i].ry,l->x,l->y));
			R=min(R,l->dis+D(p[i].lx,p[i].ly,l->x,l->y));
			s.erase(l++);
		}
		s.insert(info(p[i].lx,p[i].ry,L));
		s.insert(info(p[i].lx,p[i].ly,R));
	}
	int ans=INF;
	for(set<info>::iterator it=s.begin();it!=s.end();it++) ans=min(ans,it->dis+D(aim,0,it->x,it->y));
	cout<<ans;
	return 0;
}

T2:LOJ火锅盛宴
一个优先队列维护没熟的,一个线段树维护熟的,然后模拟就完了

#include
#define pii pair
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
#define db double
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
struct info{
	int x,id;
	info(){}
	info(int _x,int _id):x(_x),id(_id){}
	inline bool operator > (const info &rhs)const{return x>rhs.x;}
};
int n;
const int N=1e5+5;
namespace segtree{
	struct seg{int l,r,sum;}tr[N<<2];
	#define ls tr[k].l
	#define rs tr[k].r
	#define mid (ls+rs>>1)
	inline void build(int k,int l,int r){
		ls=l;rs=r;tr[k].sum=0;
		if(l==r) return;
		build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	}
	inline void modify(int k,int pos){			//op 0 
		++tr[k].sum;
		if(ls==rs) return;
		if(pos<=mid) modify(k<<1,pos);
		else modify(k<<1|1,pos);
	}
	inline int query_min(int k){			 	//op 1 
		if(!tr[k].sum) return 0;
		--tr[k].sum;
		if(ls==rs) return ls;
		if(tr[k<<1].sum) return query_min(k<<1);
		else return query_min(k<<1|1);
	}
	inline int query_pos(int k,int pos){  		//op 2
		if(!tr[k].sum) return 0;
		if(ls==rs){--tr[k].sum;return 1;}
		int res=0;
		if(pos<=mid) res=query_pos(k<<1,pos);
		else res=query_pos(k<<1|1,pos);
		tr[k].sum-=res;return res;
	}
	inline int query_seq(int k,int ql,int qr){	//op 3
		if(ql>rs || qr<ls) return 0;
		if(ql<=ls && rs<=qr) return tr[k].sum;
		if(qr<=mid) return query_seq(k<<1,ql,qr);
		else if(ql>mid) return query_seq(k<<1|1,ql,qr);
		else return query_seq(k<<1,ql,mid)+query_seq(k<<1|1,mid+1,qr);
	} 
}
using namespace segtree;
int w[N];
priority_queue<info,vector<info>,greater<info> >q;
deque<int>son[N];
inline void file(){freopen("b.in","r",stdin);freopen("b.out","w",stdout);}
int main(){
	int t=read();
	while(t--){
		n=read();build(1,1,n);
		for(int i=1;i<=n;i++) w[i]=read(),son[i].clear();
		while(!q.empty()) q.pop();
		int Q=read();
		while(Q--){
			int t=read(),op=read();
			while(q.size() && q.top().x<=t){
				int y=q.top().id;modify(1,y);
				son[y].pop_front();q.pop();
			}
			if(op==0){
				int x=read();
				son[x].push_back(t+w[x]);
				q.push(info(t+w[x],x));
			}
			else if(op==1){
				if(!tr[1].sum) puts("Yazid is angry.");
				else cout<<query_min(1)<<"\n";
			}
			else if(op==2){
	            int x=read();
				if(query_pos(1,x)) puts("Succeeded!");
                else if(son[x].size()) cout<<son[x].front()-t<<"\n";
                else puts("YJQQQAQ is angry.");
            }
            else{
				int l=read(),r=read();
				cout<<query_seq(1,l,r)<<"\n";
			}
		}
	}
	return 0;
}

T3:给出一个多边形的三角剖分,求一个由多边形顶点构成的三角形使得它与尽量多的三角形有交,求最大交数
构造一个对偶图(不包含最外面那个平面),一定是一棵树,然后树上一条连接两个叶子的路径对应一种连两个顶点交三角形的方案,且数量就是路径长度
则我们要找一个三角形就是三条路径,树形dp即可

Code:

#include
#define pii pair
#define mp make_pair
#define pb push_back
#define ll long long 
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1e5+5;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
map<pii,int>m;
int n,cnt=0,ans=0;
int h[N];
void dfs1(int v,int fa){
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(y==fa) continue;
		dfs1(y,v);
		h[v]=max(h[v],h[y]);
	}
	++h[v];
}
void dfs2(int v,int fa,int val){
	int dp[2];dp[0]=dp[1]=0;
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(y==fa) continue;
		if(h[y]>dp[0]) dp[1]=dp[0],dp[0]=h[y];
		else if(h[y]>dp[1]) dp[1]=h[y];
	}
	ans=max(ans,val+1);
	ans=max(ans,dp[0]+val+1);
	ans=max(ans,dp[0]+dp[1]+val+1);
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(y==fa) continue;
		if(h[y]!=dp[0]) dfs2(y,v,max(val,dp[0])+1);
		else dfs2(y,v,max(val,dp[1])+1);
	}
}
int main(){
	n=read();
	for(int i=0;i<n-2;i++){
		static int seq[3];
		for(int j=0;j<3;j++) seq[j]=read();
		sort(seq,seq+3);
		for(int j=0;j<2;j++)
			for(int k=j+1;k<3;k++) if(m.count(mp(seq[j],seq[k]))){
				add(cnt,m[mp(seq[j],seq[k])]);
				add(m[mp(seq[j],seq[k])],cnt);
			}
		for(int j=0;j<2;j++)
			for(int k=j+1;k<3;k++)
				m[mp(seq[j],seq[k])]=cnt;
		++cnt;
	}
	dfs1(0,-1);dfs2(0,-1,0);
	cout<<ans;
	return 0;
}

你可能感兴趣的:(线段树,树形DP,平面图)