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

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

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('\n');return;}
	if(x<0){putchar('-'),x=-x;}
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
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('\n');return;}
	if(x<0){putchar('-'),x=-x;}
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
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('\n');return;}
	if(x<0){putchar('-'),x=-x;}
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
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
*/

 

posted @ 2018-08-07 17:15  echo6342  阅读(396)  评论(0编辑  收藏  举报