• 并不对劲的素质四连(一)


    并不对劲的片手流还没有醒过来,却要做某铝质紫色大剑的题,感到十分不爽,因此称之为“素质四连”。

    d1t1

    题意:给一棵n个点的树,q次询问,每次询问一条路径上的点权最小值,n,q<=1e5

    做法:不穿衣服的Lca裸题,正常倍增或正常树剖

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<set>
    #include<stack>
    #include<vector>
    #define maxn 100010
    #define maxm 200010
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	char ch[20];int f=0;
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	if(x<0){putchar('-'),x=-x;}
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    int fir[maxn],nxt[maxm],v[maxm],w[maxn],cnt;
    int anc[maxn][21],minw[maxn][21],dep[maxn],n,q;
    void ade(int u1,int v1){v[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
    void getanc(int u)
    {
    	for(int i=1;i<=19;i++)anc[u][i]=anc[anc[u][i-1]][i-1],minw[u][i]=min(minw[u][i-1],minw[anc[u][i-1]][i-1]);
    	for(int k=fir[u];k!=-1;k=nxt[k])
    	{
    		if(v[k]!=anc[u][0])
    		{
    			anc[v[k]][0]=u,dep[v[k]]=dep[u]+1,minw[v[k]][0]=min(w[u],w[v[k]]);
    			getanc(v[k]);
    		}
    	}
    }
    int lca(int x,int y)
    {
    	int ans=min(w[x],w[y]);
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)if(dep[anc[x][i]]>=dep[y])ans=min(ans,minw[x][i]),x=anc[x][i];
    	if(x==y)return ans;
    	for(int i=19;i>=0;i--)
    		if(anc[x][i]!=anc[y][i])
    		    ans=min(ans,min(minw[x][i],minw[y][i])),y=anc[y][i],x=anc[x][i];
    	if(x!=y)ans=min(ans,min(minw[x][0],minw[y][0]));
    	return ans;
    }
    int main()
    {
    	freopen("min.in","r",stdin);
    	freopen("min.out","w",stdout);
    	memset(fir,-1,sizeof(fir));
    	memset(minw,0x7f,sizeof(minw));
    	n=read(),q=read();
    	for(int i=1;i<=n;i++)w[i]=read();
    	for(int i=1;i<n;i++){int x=read(),y=read();ade(x,y),ade(y,x);}
    	minw[1][0]=w[1];
    	getanc(1);
    	while(q--)
    	{
    		int x=read(),y=read();
    		write(lca(x,y));
    	}
    	return 0;
    }
    

    d1t2

    题意:有一个有n个数的数列,q次询问,每次问所有子区间中异或和第k大的,n<=10^4,q<=10^5,数列中的数<=2^20

    做法:求前缀异或和s[i],那么区间[l,r]的异或和就是s[l-1]^s[r],这样可以枚举所有s[i]^s[j],桶排序,询问时直接输出第k个(没想到吧?)

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<set>
    #include<stack>
    #include<vector>
    #define maxn 10010
    #define maxa 1048576
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	char ch[20];int f=0;
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	if(x<0){putchar('-'),x=-x;}
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    int xo[maxa+1],s[maxn],a[maxn],n,q,cnt;
    int main()
    {
    	freopen("xor.in","r",stdin);
    	freopen("xor.out","w",stdout);
    	n=read(),q=read();
    	for(int i=1;i<=n;++i)a[i]=read(),s[i]=s[i-1]^a[i];
    	if(n<=1000)
    	{
    		for(int i=0;i<=n;i++)
    			for(int j=i+1;j<=n;j++)
    			    xo[++cnt]=s[i]^s[j];
    		sort(xo+1,xo+cnt+1);
    		while(q--)
    		{
    			int x=read();
    			write(xo[x]);
    		}
    	}
    	else
    	{
    		for(int i=0;i<=n-1;++i)for(int j=i+1;j<=n;++j)++xo[s[i]^s[j]];
    		for(int i=1;i<maxa;++i)xo[i]+=xo[i-1];
    		while(q--)
    		{
    			int x=read(),L=0,R=maxa-1,ans=-1;
    			while(L<=R)
    			{
    				int mid=(L+R)>>1;
    				if(xo[mid]<x)ans=max(mid,ans),L=mid+1;
    				else R=mid-1;
    			}
    			ans++;
    			write(ans);
    		}
    	}
    	return 0;
    }
    

    d1t3

    题意:有n个点,m个条件,每个条件有l,r,v,表示点的编号在[l,r]中的任意两点之间都有一条权值为v的边,求最小生成树

    做法:因为标程是并查集,这里就写个不一样的吧。可以先将所有条件按v排序,那么考虑到第i个条件时,会发现区间[li,ri]中所有点还未连通的最好都在此时连通。那么区间[li,ri]就会属于同一个连通块。这个刚好可以用线段树的区间覆盖解决。

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<set>
    #include<stack>
    #include<vector>
    #define maxn 100010
    #define mi (l+r>>1)
    #define ls (u<<1)
    #define rs (u<<1|1)
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	char ch[20];int f=0;
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	if(x<0){putchar('-'),x=-x;}
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    struct Q{int l,r,v;bool operator <(const Q &z)const{return v<z.v;}}q[maxn];
    typedef struct node{int hd,tl,num;}X;
    X make_x(int hd1,int tl1,int num1){X tmp;tmp.hd=hd1,tmp.tl=tl1,tmp.num=num1;return tmp;}
    X tr[maxn<<2];
    int n,m,mk[maxn<<2];
    X pu(X x,X y)
    {
    	if(x.hd==0)return y;
    	if(y.hd==0)return x;
    	int num=x.num+y.num;
    	if(x.tl==y.hd)num--;
    	return make_x(x.hd,y.tl,num);
    }
    void mark(int u,int l,int r,int k){tr[u].num=1,tr[u].hd=tr[u].tl=k,mk[u]=k;return;}
    void pd(int u,int l,int r){if(mk[u]&&l<r)mark(ls,l,mi,mk[u]),mark(rs,mi+1,r,mk[u]),mk[u]=0;}
    void build(int u,int l,int r)
    {
    	if(l==r){mark(u,l,r,l);return ;}
    	build(ls,l,mi),build(rs,mi+1,r),tr[u]=pu(tr[ls],tr[rs]);return;
    }
    X ask(int u,int l,int r,int x,int y)
    {
    	pd(u,l,r);
    	if(x<=l&&r<=y){return tr[u];}
    	if(y<l||r<x)return make_x(0,0,0);
    	return pu(ask(ls,l,mi,x,y),ask(rs,mi+1,r,x,y));
    }
    void add(int u,int l,int r,int x,int y,int k)
    {
    	pd(u,l,r);
    	if(x<=l&&r<=y){mark(u,l,r,k);return;}
    	if(y<l||r<x)return;
    	add(ls,l,mi,x,y,k),add(rs,mi+1,r,x,y,k),tr[u]=pu(tr[ls],tr[rs]);return;
    }
    int main()
    {
    	freopen("kruskal.in","r",stdin);
    	freopen("kruskal.out","w",stdout);
    	n=read(),m=read();
    	for(int i=1;i<=m;i++)q[i].l=read(),q[i].r=read(),q[i].v=read();
    	sort(q+1,q+m+1);
    	build(1,1,n);
    	int ans=0;
    	for(int i=1;i<=m;i++)
    	{
    		X f=ask(1,1,n,q[i].l,q[i].r);
    		ans+=(f.num-1)*q[i].v;
    		int tail=q[i].r,L=q[i].r,R=n;
    		while(L<=R)
    		{
    			int mid=(L+R>>1);
    			X tmp=ask(1,1,n,q[i].l,mid);
    			if(tmp.num==f.num)tail=max(tail,mid),L=mid+1;
    			else R=mid-1;
    		}
    		add(1,1,n,q[i].l,tail,f.hd);
    	}
    	X f=ask(1,1,n,1,n);
    	if(f.num!=1)puts("-1");
    	else write(ans);
    	return 0;
    }
    /*
    10 8
    2 5 2
    4 7 1
    8 8 3 
    8 10 4
    2 5 5
    5 7 6
    7 10 7
    1 2 8
    */
    
  • 相关阅读:
    编译原理 —— 正规式、正规集和正则定义
    NFA的确定化
    第三章 词法分析与有限自动机
    文法:0型【短语文法】、1型【上下文有关文法】、2型【上下文无关文法】、3型【正规文法】
    语法树、短语、直接短语、句柄、素短语、最左素短语
    【第1章 编译概述】1.2编译程序的发展
    【第1章 编译概述】1.2编译的各个阶段
    【第1章 编译概述】1.1 编译程序功能
    【第1章 编译概述】1.1 程序设计语言
    【第9章 目标代码生成】9.3 简单代码生成器
  • 原文地址:https://www.cnblogs.com/xzyf/p/9438156.html
Copyright © 2020-2023  润新知