• Comet OJ


    Contest14的本质:区间覆盖+Tarjan(

    A

    把距离公式两边平方即可

    注意要long long

    code

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    using namespace std;
    
    int x[100001];
    int y[100001];
    int n,i,j,k,l,X,Y,R,ans;
    
    int main()
    {
    //	freopen("a.in","r",stdin);
    	
    	scanf("%d%d%d%d",&n,&X,&Y,&R);
    	fo(i,1,n)
    	scanf("%d%d",&x[i],&y[i]);
    	
    	fo(i,1,n)
    	if (((long long)(x[i]-X)*(x[i]-X)+(long long)(y[i]-Y)*(y[i]-Y))<=(long long)R*R)
    	++ans;
    	
    	printf("%d
    ",ans);
    }
    

    B

    显然p和k是位置最靠边的两个

    考虑一下i和n的位置(靠左/靠右/左右)

    code

    比较丑

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define max(a,b) (a>b?a:b)
    using namespace std;
    
    char a[1000001];
    int T,n,i,j,k,l,ans,s1,s2,s3,s4;
    char ch;
    
    int main()
    {
    //	freopen("b.in","r",stdin);
    	
    	scanf("%d",&T);
    	for (;T;--T)
    	{
    		ans=-1;
    		scanf("%d",&n);
    		
    		fo(i,1,n)
    		{
    			ch=getchar();
    			while (ch<'a' || ch>'z')
    			ch=getchar();
    			
    			a[i]=ch;
    		}
    		
    		fo(i,1,n)
    		if (a[i]=='p')
    		break;
    		
    		fd(j,n,1)
    		if (a[j]=='k')
    		break;
    		
    		fo(k,i+1,n)
    		if (a[k]=='i')
    		break;
    		
    		fo(l,k+1,n)
    		if (a[l]=='n')
    		break;
    		if (i>=1 && i<k && k<l && l<j && j<=n && a[i]=='p' && a[k]=='i' && a[l]=='n' && a[j]=='k')
    		ans=max(ans,max(max(k-i-1,l-k-1),j-l-1));
    		
    		fd(l,j-1,k+1)
    		if (a[l]=='n')
    		break;
    		if (i>=1 && i<k && k<l && l<j && j<=n && a[i]=='p' && a[k]=='i' && a[l]=='n' && a[j]=='k')
    		ans=max(ans,max(max(k-i-1,l-k-1),j-l-1));
    		
    		fd(l,j-1,1)
    		if (a[l]=='n')
    		break;
    		fd(k,l-1,i+1)
    		if (a[k]=='i')
    		break;
    		if (i>=1 && i<k && k<l && l<j && j<=n && a[i]=='p' && a[k]=='i' && a[l]=='n' && a[j]=='k')
    		ans=max(ans,max(max(k-i-1,l-k-1),j-l-1));
    		
    		printf("%d
    ",ans);
    	}
    }
    

    C

    区间覆盖*1

    一开始以为一对区间只能算一次答案

    维护断点,那么一种方案=断点数-1(加上首尾)

    一次覆盖后,区间外的不变,区间内的变为0,边界变为1

    所以可以合在一起维护,区间外的*2,区间内的不变,边界+2^(i-1)

    i的答案为断点总数-2^i

    code

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define mod 20050321
    using namespace std;
    
    long long p[2001];
    int L[2001];
    int R[2001];
    bool b[2001];
    long long sum[2001];
    long long Sum[2001];
    int n,m,i,j,k,l;
    long long ans;
    
    int main()
    {
    //	freopen("c.in","r",stdin);
    	
    	scanf("%d%d",&n,&m);
    	p[0]=1;
    	fo(i,1,m)
    	{
    		scanf("%d%d",&L[i],&R[i]);
    		p[i]=p[i-1]*2%mod;
    	}
    	
    	sum[0]=sum[n]=1;
    	fo(i,1,m)
    	{
    		fo(j,0,n) Sum[j]=sum[j];
    		fo(j,0,L[i]-2) Sum[j]=(Sum[j]+sum[j])%mod;
    		fo(j,R[i]+1,n) Sum[j]=(Sum[j]+sum[j])%mod;
    		Sum[L[i]-1]=(Sum[L[i]-1]+p[i-1])%mod;
    		Sum[R[i]]=(Sum[R[i]]+p[i-1])%mod;
    		
    		ans=0;
    		fo(j,0,n)
    		sum[j]=Sum[j],Sum[j]=0,ans=(ans+sum[j])%mod;
    		
    		printf("%lld
    ",(ans-p[i]+mod)%mod);
    	}
    }
    

    D

    区间覆盖*2

    套路,询问若一段操作的结果就把询问离线按r排序,每次加一个操作计算答案

    维护每一段区间的两个端点(左右括号),那么每加一个区间最多加4个括号,每个括号只会被删一次

    每加一个区间,就相当于把中间的端点删掉(大的能覆盖掉小的),再在两边加上新的端点

    询问就是求每个修改所剩余的个数*权值的后缀和

    用set维护括号,每次断开后找中间的区间,用树状数组维护答案

    code

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <set>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define low(x) (x&-(x))
    using namespace std;
    
    struct qs{
    	int l,r,id;
    } q[500001];
    struct type{
    	int x,s,t; //0=right 1=left
    	bool friend operator < (type a,type b) {return a.x<b.x || a.x==b.x && a.t<b.t;}
    };
    int a[500001][3];
    long long ans[500001];
    long long tr[500001];
    multiset<type> st;
    multiset<type> :: iterator I,J;
    int n,m,Q,i,j,k,l;
    
    bool cmp(qs a,qs b)
    {
    	return a.r<b.r;
    }
    
    void change(int t,long long s)
    {
    	while (t<=n)
    	{
    		tr[t]+=s;
    		t+=low(t);
    	}
    }
    long long find(int t)
    {
    	long long ans=0;
    	
    	while (t)
    	{
    		ans+=tr[t];
    		t-=low(t);
    	}
    	
    	return ans;
    }
    
    int main()
    {
    //	freopen("d.in","r",stdin);
    	
    	scanf("%d%d%d",&n,&m,&Q);
    	fo(i,1,n)
    	scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
    	fo(i,1,Q)
    	scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    	
    	sort(q+1,q+Q+1,cmp);
    	
    	st.insert({0,0,1});
    	st.insert({m,0,0});
    	fo(i,1,Q)
    	{
    		fo(j,q[i-1].r+1,q[i].r)
    		{
    			I=st.lower_bound({a[j][0]-1,0,1});
    			if (I!=st.begin())
    			{
    				--I;
    				if ((*I).x<a[j][0]-1)
    				{
    					k=(*I).s;
    					st.insert({a[j][0]-1,k,0});
    					st.insert({a[j][0]-1,k,1});
    				}
    			}
    			
    			I=st.upper_bound({a[j][1],0,0});
    			if (I!=st.end())
    			{
    				if (a[j][1]<(*I).x)
    				{
    					k=(*I).s;
    					st.insert({a[j][1],k,0});
    					st.insert({a[j][1],k,1});
    				}
    			}
    			
    			I=st.lower_bound({a[j][0]-1,0,1});
    			J=st.upper_bound({(*I).x,0,1});
    			while (I!=st.end() && (*I).x<a[j][1])
    			{
    				if ((*I).s)
    				change((*I).s,-(long long)a[(*I).s][2]*((*J).x-(*I).x));
    				
    				st.erase(I);
    				J=st.lower_bound({a[j][0]-1,0,1});
    				st.erase(J);
    				
    				I=st.lower_bound({a[j][0]-1,0,1});
    				J=st.upper_bound({(*I).x,0,1});
    			}
    			
    			st.insert({a[j][0]-1,j,1});
    			st.insert({a[j][1],j,0});
    			change(j,(long long)a[j][2]*(a[j][1]-a[j][0]+1));
    		}
    		
    		ans[q[i].id]=find(q[i].r)-find(q[i].l-1);
    	}
    	
    	fo(i,1,Q)
    	printf("%lld
    ",ans[i]);
    }
    

    E

    Tarjan*1

    这应该是除了那道简单数论以外最水的E了

    Tarjan缩强联通分量,dp维护从起点到每个点的最小边权、最大边权、最大差值

    正确性:最大差值与路径上的最大&最小值有关,那么一定会在找到后面那个(大or小)的时候与另一个计算到

    注意细节,考虑极值所在位置(原点、边、新点)

    code

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    using namespace std;
    
    int a[500001][3];
    int ls[200001];
    int A[500001][3];
    int Ls[200001];
    int dfn[200001];
    int low[200001];
    int d[200001];
    int D[200001];
    int mx[200001];
    int mn[200001];
    bool bz[200001];
    int num[200001];
    int f[200001][3]; //mn,mx,ans
    int n,m,Q,i,j,k,l,len,Len,tot,h,t;
    
    void New(int x,int y,int z)
    {
    	++len;
    	a[len][0]=y;
    	a[len][1]=ls[x];
    	ls[x]=len;
    	a[len][2]=z;
    }
    void NEW(int x,int y,int z)
    {
    	++Len;
    	A[Len][0]=y;
    	A[Len][1]=Ls[x];
    	Ls[x]=Len;
    	A[Len][2]=z;
    	
    	++D[y];
    }
    
    void dfs(int t)
    {
    	int i;
    	
    	++j;
    	dfn[t]=j;
    	low[t]=j;
    	bz[t]=1;
    	d[++l]=t;
    	
    	for (i=ls[t]; i; i=a[i][1])
    	{
    		if (!dfn[a[i][0]])
    		{
    			dfs(a[i][0]);
    			low[t]=min(low[t],low[a[i][0]]);
    		}
    		else
    		if (bz[a[i][0]])
    		low[t]=min(low[t],dfn[a[i][0]]);
    	}
    	
    	if (dfn[t]==low[t])
    	{
    		++tot;
    		while (d[l]!=t)
    		{
    			bz[d[l]]=0;
    			num[d[l--]]=tot;
    		}
    		bz[d[l]]=0;
    		num[d[l--]]=tot;
    	}
    }
    
    int main()
    {
    //	freopen("e.in","r",stdin);
    //	freopen("b.out","w",stdout);
    	
    	scanf("%d%d%d",&n,&m,&Q);
    	fo(i,1,m)
    	{
    		scanf("%d%d%d",&j,&k,&l);
    		New(j,k,l);
    	}
    	
    	memset(mx,190,sizeof(mx));
    	memset(mn,60,sizeof(mn));
    	j=l=0;
    	dfs(1);
    	
    	fo(j,1,n)
    	if (num[j])
    	{
    		for (i=ls[j]; i; i=a[i][1])
    		if (num[a[i][0]])
    		{
    			if (num[j]==num[a[i][0]])
    			{
    				mx[num[j]]=max(mx[num[j]],a[i][2]);
    				mn[num[j]]=min(mn[num[j]],a[i][2]);
    			}
    			else
    			NEW(num[j],num[a[i][0]],a[i][2]);
    		}
    	}
    	
    	h=t=0;
    	fo(i,1,tot)
    	if (!D[i])
    	d[++t]=i;
    	
    	fo(i,1,tot)
    	{
    		f[i][0]=mn[i];
    		f[i][1]=mx[i];
    		f[i][2]=f[i][1]-f[i][0];
    	}
    	while (h<t)
    	{
    		for (i=Ls[d[++h]]; i; i=A[i][1])
    		{
    			f[A[i][0]][0]=min(f[A[i][0]][0],min(f[d[h]][0],A[i][2]));
    			f[A[i][0]][1]=max(f[A[i][0]][1],max(f[d[h]][1],A[i][2]));
    			
    			f[A[i][0]][2]=max(f[A[i][0]][2],A[i][2]-f[d[h]][0]);
    			f[A[i][0]][2]=max(f[A[i][0]][2],mx[A[i][0]]-f[d[h]][0]);
    			f[A[i][0]][2]=max(f[A[i][0]][2],mx[A[i][0]]-A[i][2]);
    			
    			f[A[i][0]][2]=max(f[A[i][0]][2],f[d[h]][1]-A[i][2]);
    			f[A[i][0]][2]=max(f[A[i][0]][2],f[d[h]][1]-mn[A[i][0]]);
    			f[A[i][0]][2]=max(f[A[i][0]][2],A[i][2]-mn[A[i][0]]);
    			
    			f[A[i][0]][2]=max(f[A[i][0]][2],max(f[d[h]][2],0));
    			
    			--D[A[i][0]];
    			if (!D[A[i][0]])
    			d[++t]=A[i][0];
    		}
    	}
    	
    	for (;Q;--Q)
    	{
    		scanf("%d",&j);
    		if (num[j] && f[num[j]][2]>=0)
    		printf("%d
    ",f[num[j]][2]);
    		else
    		printf("-1
    ");
    	}
    }
    

    F

    Tarjan*2

    显然可以求出相交关系然后求割点,用主席树优化连边

    口胡一下

    按横/竖顺序扫描线,考虑相交线段a和b

    a在加入时由叶子连向a,b在查找时由b连向询问区间

    每个区间向儿子连边,询问时新建叶节点时就向原叶节点连边,如果是删除一段线段就不连

    一次修改or询问的操作节点和连边数为log n级别

    两种顺序搞完之后Tarjan求割点即可

    code

    没写

  • 相关阅读:
    【get√】发现一个redis zset的新玩法:用ZINTERSTORE把value都置0
    【记录一个问题】golang神坑,明明返回了接口指针类型的nil值,却无法用if判断
    【记录一个问题】神坑,自定义一个golang的error类型,居然运行崩溃了
    【解决了一个小问题】golang protocol buffers 3中去掉json标签中的omitempty
    【转载】select case break引发的血案
    【记录一个问题】redis中执行事务出现错误“EXECABORT Transaction discarded because of previous errors”
    【get√】golang中实现从腾讯云CVM查询网卡流量的两种方法
    【get√】golang新手理解了一点点context
    【get√】golang新手理解了一点点gin框架的中间件
    1066. 图像过滤(15)
  • 原文地址:https://www.cnblogs.com/gmh77/p/11827296.html
Copyright © 2020-2023  润新知