zoukankan      html  css  js  c++  java
  • [正睿集训2021] 杂题选讲

    CF983D Arkady and Rectangles

    题目描述

    点此看题

    解法

    这种矩形覆盖的题一定要去想扫描线了,我们把矩形按 (x) 坐标排序,在某个 (x) 加入,在某个 (x) 删除。那么每次就只需要考虑 (y) 坐标了,维护 (y) 坐标可以用线段树。

    下面的维护方法就有点神奇了,每次就考虑哪些颜色没有被覆盖,对于线段树的每个节点维护 (mx[i]) 表示 (i) 节点的区间内最大的没有被看见的眼色,(mi[i]) 表示在这个区间内如果要被看到颜色至少需要多大。再用一个 (set) 维护覆盖该区间的所有颜色,上传的方式是这样:

    mx[o]=max(mx[o<<1],mx[o<<1|1]);
    mi[o]=min(mi[o<<1],mi[o<<1|1]);
    if(!s[o].empty()) return;
    int hh=*s[o].rbegin();
    mi[o]=max(hh,mi[o]);
    if(hh>mx[o])
    {
    	if(vis[hh] || hh<mi[o]) mx[o]=0;
    	else mx[o]=hh;
    }
    

    很简洁,但是很难想

    代码实现还有一个小细节,离散化的时候假设端点为 (x),把 (x-1,x,x+1) 都离散化一下。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <set>
    using namespace std;
    const int M = 600005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,ans,mx[4*M],mi[4*M];set<int> s[4*M];
    int vis[M],xl[M],xr[M],yl[M],yr[M],p[M];
    struct node
    {
    	int x,l,r,id;
    	bool operator < (const node &R) const
    	{
    		return x<R.x;
    	}
    }a[M];
    void up(int i,int l,int r)
    {
    	int hh=s[i].size()?(*s[i].rbegin()):0;
    	if(l==r) mx[i]=mi[i]=hh;
    	else
    	{
    		mx[i]=max(hh,max(mx[i<<1],mx[i<<1|1]));
    		mi[i]=max(hh,min(mi[i<<1],mi[i<<1|1]));
    	}
    	if(vis[mx[i]] || mx[i]<mi[i])
    		mx[i]=0;
    }
    void ins(int i,int l,int r,int L,int R,int x)
    {
    	if(L>r || l>R) return ;
    	if(L<=l && r<=R)
    	{
    		
    		if(x>0) s[i].insert(x);
    		else s[i].erase(-x);
    		up(i,l,r);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	ins(i<<1,l,mid,L,R,x);
    	ins(i<<1|1,mid+1,r,L,R,x);
    	up(i,l,r);
    }
    void upd(int i,int l,int r,int L,int R)
    {
    	if(L>r || l>R) return ;
    	if(L<=l && r<=R) {up(i,l,r);return ;}
    	int mid=(l+r)>>1;
    	upd(i<<1,l,mid,L,R);
    	upd(i<<1|1,mid+1,r,L,R);
    	up(i,l,r);
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		xl[i]=read();
    		p[++k]=yl[i]=read();
    		p[++k]=yl[i]-1;
    		p[++k]=yl[i]+1; 
    		xr[i]=read();
    		p[++k]=yr[i]=read()-1;
    		p[++k]=yr[i]-1;
    		p[++k]=yr[i]+1;
    	}
    	sort(p+1,p+1+k);
    	k=unique(p+1,p+1+k)-p-1;//必须要这样 
    	for(int i=1;i<=n;i++)
    	{
    		yl[i]=lower_bound(p+1,p+1+k,yl[i])-p;
    		yr[i]=lower_bound(p+1,p+1+k,yr[i])-p;
    		a[++m]=node{xl[i],yl[i],yr[i],i};
    		a[++m]=node{xr[i],yl[i],yr[i],-i};
    	}
    	sort(a+1,a+1+m);
    	for(int i=1,j;i<=m;i=j)
    	{
    		for(j=i;a[j].x==a[i].x;j++)
    		{
    			//printf("->%d %d %d
    ",a[j].id,a[j].l,a[j].r);
    			ins(1,1,k,a[j].l,a[j].r,a[j].id);
    		}
    		while(mx[1])
    		{
    			int c=mx[1];ans++;
    			//printf("%d %d %d
    ",c,yl[c],yr[c]);
    			vis[c]=1;//删除这个颜色
    			upd(1,1,k,yl[c],yr[c]);//区间更新一下 
    		}
    	}
    	printf("%d
    ",ans+1);
    }
    

    Sunčanje

    题目描述

    点此看题

    解法

    题目转移有亿点巧妙,我们去统计有多少编号大于他的矩形和他不交,如果都和他不交那么他就完全暴露在阳光下了。

    这个统计就是一个容斥,我们把四边延长成九宫格然后统计 上(/)(/)(/)右 的答案之后,减去 左上(/)左下(/)右上(/)右下 的答案即可。

    左上(/)左下(/)右上(/)右下 的计算需要三维偏序,所以写 (cdq) 分治就可以计算了。

    CF650E Clockwork Bomb

    题目描述

    点此看题

    解法

    这种题可以叫做树上的构造问题,那么一定要去考虑 (dfs) 的方式解决。

    首先如果边 ((x,y)) 在两棵树上都出现的话,我们尝试不动他,只改变那些不合法的边,如果能做到那么就是最少的方案数。

    考虑在第一棵树上 (dfs),那么每次 (u) 访问儿子 (v) 时我们就看 ((u,v)) 这条边是否在第二棵树上出现过,如果没有出现过我们就要调整它,设第二棵树上的父亲为 (f2),就可能会出现第一棵树上已经有了 ((u,f2)) 这条边的情况,不能直接连。

    但是这条边一定是有地方放的,我们考虑初始时在第一棵树上保留已经合法的边,而且父子关系用第二棵树上的,那么 (u) 连通块的根一定还没有连接,我们连接 ((rt,f2[rt])) 这条边即可,如果 (f2[rt])(u) 祖先方向不会构成环,如果在儿子方向会不会构成环呢?因为 (dfs) 已经把儿子处的结构处理好了,所以现在放心的连是没问题的。

    #include <cstdio>
    #include <vector>
    using namespace std;
    const int M = 500005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,f1[M],f2[M],fa[M];vector<int> g1[M],g2[M];
    struct node
    {
    	int a,b,c,d;
    }s[M];
    void dfs1(int u,int p)
    {
    	f1[u]=p;
    	for(int i=0;i<g1[u].size();i++)
    	{
    		int v=g1[u][i];
    		if(v==p) continue;
    		dfs1(v,u);
    	}
    }
    void dfs2(int u,int p)
    {
    	f2[u]=p;
    	for(int i=0;i<g2[u].size();i++)
    	{
    		int v=g2[u][i];
    		if(v==p) continue;
    		dfs2(v,u);
    	}
    }
    int find(int x)
    {
    	if(x!=fa[x]) fa[x]=find(fa[x]);
    	return fa[x];
    }
    void dfs(int u)
    {
    	for(int i=0;i<g1[u].size();i++)
    	{
    		int v=g1[u][i];
    		if(v==f1[u]) continue;
    		dfs(v);
    		if(f2[u]!=v && f2[v]!=u)
    			s[++m]=node{u,v,find(v),f2[find(v)]};
    	}
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		g1[u].push_back(v);
    		g1[v].push_back(u);
    	}
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		g2[u].push_back(v);
    		g2[v].push_back(u);
    	}
    	dfs1(1,0);
    	dfs2(1,0);
    	for(int i=1;i<=n;i++)
    	{
    		int j=f2[i];
    		if(f1[i]==j || f1[j]==i) fa[i]=j;
    		else fa[i]=i;
    	}
    	dfs(1);
    	printf("%d
    ",m);
    	for(int i=1;i<=m;i++)
    		printf("%d %d %d %d
    ",s[i].a,s[i].b,s[i].c,s[i].d);
    }
    
  • 相关阅读:
    Hdu 5445 Food Problem (2015长春网络赛 ACM/ICPC Asia Regional Changchun Online)
    Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)
    大数模板 (C ++)
    后缀数组 DC3构造法 —— 详解
    后缀数组 (倍增法) 个人理解
    Hdu 2888 Check Corners (二维RMQ (ST))
    Marriage Match IV---hdu3416(spfa + Dinic)
    The Shortest Path in Nya Graph---hdu4725(spfa+扩点建图)
    Tram---poj1847(简单最短路)
    昂贵的聘礼---poj1062(最短路)
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14473787.html
Copyright © 2011-2022 走看看