zoukankan      html  css  js  c++  java
  • 20200820校测

    T1:

    给出一个n个点的图,编号依次为1~n。编号为i和j的两点之间边权为c*(i^j)(c为给定常数)
    另外还有m条边,边权给定。给出A,B,求出A到B的最短路
    题目链接

    solution:

    考虑异或这种操作。其实不用建出n*n条边,只需要如此建边:
    比如5(101)号节点,只用向4(100),7(111),1(001)连边即可
    即向每一个二进制位取异或连边
    而比如5(101)到6(110)的边,可通过5(101)到4(100)到6(110)如此到达
    注意下0号节点也需要连边

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    typedef pair<int,int> pii;
    int n,m,c,h,st,ed;
    struct edge{int to,w;};
    vector<edge>v[N];
    inline int dijkstra()
    {
    	int d[N];fill(d,d+n+1,1e9);
    	d[st]=0;
    	priority_queue<pii,vector<pii>,greater<pii> >pq;
    	pq.push(make_pair(0,st));
    	while(!pq.empty())
    	{
    		int u=pq.top().second;pq.pop();
    		for(int i=0;i<v[u].size();++i)
    		{
    			int j=v[u][i].to,w=v[u][i].w;
    			if(d[j]>d[u]+w)
    			{
    				d[j]=d[u]+w;
    				pq.push(make_pair(d[j],j));
    			}
    		}
    	}
    	return d[ed];
    }
    int main()
    {
    	scanf("%d%d%d",&n,&m,&c);
    	for(h=0;(1<<h)<=n;++h);
    	for(int i=1;i<=m;++i)
    	{
    		int f,t,vv;scanf("%d%d%d",&f,&t,&vv);
    		v[f].push_back({t,vv});
    	}
    	for(int i=0;i<=n;++i)
    		for(int j=0;j<=h;++j)
    		{
    			int k=i^(1<<j);
    			if(k>n)continue;
    			v[i].push_back({k,(1<<j)*c});
    		}
    	scanf("%d%d",&st,&ed);
    	cout<<dijkstra();
    	return 0;
    }
    

    T2:

    在字节山脉有n座山峰,每座山峰有它的高度。有些山峰之间有双向道路相连,共m条路径,每条路径有一个困难值,这个值越大表示越难走,现在有q组询问,每组询问询问从点开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
    (n<=10^5,m,q<=5*10^5)
    山峰高度(hi<=10^9)
    题目链接

    solution:

    首先对整个图用kruskal求出kruskal重构树
    而后对于每一个询问,通过在重构树上倍增求出它所对应的区间
    问题转化为静态区间第k大,上主席树即可
    需要注意:kruskal重构树节点的val要初始化
    另外主席树注意空间开够及一些小细节
    部分实现可以封装简化

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+5,maxm=6e5+5;
    int N,M,Q,T,cnt,H[maxn],B[maxn];
    int Fa[maxn];
    int Nd,ch[maxn<<1][2],val[maxn<<1],nH[maxn],st[maxn<<1],ed[maxn<<1];
    int pr[maxn<<1][20];
    int rt[maxn],o,l[maxn*40],r[maxn*40],s[maxn*40];
    vector<int>new_H;
    struct Smer{int num,id;}_H[maxn];
    struct edge{int fr,to,w;}e[maxm];
    inline int read()
    {
    	int s=0,w=1; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    	return s*w;
    }
    inline bool cmp1(Smer x,Smer y){return x.num<y.num;}
    inline bool cmp2(Smer x,Smer y){return x.id<y.id;}
    inline bool cmp(edge x,edge y){return x.w<y.w;}
    int fd(int x){return Fa[x]==x?x:Fa[x]=fd(Fa[x]);}
    inline void smer()
    {
    	Smer cpyH[maxn];cnt=0;
    	for(int i=1;i<=N;++i)
    		cpyH[i].num=H[i],cpyH[i].id=i;
    	sort(cpyH+1,cpyH+N+1,cmp1);
    	for(int i=1;i<=N;++i)
    	{
    		if(i==1||cpyH[i].num!=cpyH[i-1].num)_H[i].num=++cnt;
    		else _H[i].num=cnt;
    		_H[i].id=cpyH[i].id;
    	}
    	sort(_H+1,_H+N+1,cmp2);
    	for(int i=1;i<=N;++i)B[_H[i].num]=H[i];
    }
    inline void kruskal()
    {
    	memset(val,127,sizeof(val));
    	fill(val+1,val+N+1,0);
    	for(int i=1;i<=N*2;++i)Fa[i]=i;
    	sort(e+1,e+M+1,cmp);
    	Nd=N;
    	int ct=0;
    	for(int i=1;i<=M;++i)
    	{
    		int aa=e[i].fr,bb=e[i].to;
    		int faa=fd(aa),fbb=fd(bb);
    		if(faa==fbb)continue;
    		++ct;
    		val[++Nd]=e[i].w;
    		ch[Nd][0]=faa;ch[Nd][1]=fbb;
    		Fa[faa]=Fa[fbb]=Nd; 
    		if(ct==N-1)break;
    	}
    }
    void dfs(int pos,int depth,int Pr)
    {
    	pr[pos][0]=Pr;
    	for(int i=1;(1<<i)<=depth;++i)
    		pr[pos][i]=pr[pr[pos][i-1]][i-1];
    	if(!val[pos])
    	{
    		st[pos]=ed[pos]=new_H.size();
    		new_H.push_back(pos);
    		return;
    	}
    	dfs(ch[pos][0],depth+1,pos);dfs(ch[pos][1],depth+1,pos);
    	st[pos]=st[ch[pos][0]];ed[pos]=ed[ch[pos][1]];
    }
    inline void get_interval(int pos,int _val,int &ll,int &rr)
    {
    	for(int i=19;i>=0;--i)
    		if(val[pr[pos][i]]<=_val)
    			pos=pr[pos][i];
    	ll=st[pos];rr=ed[pos];
    }
    void update(int &_rt,int pre_rt,int p,int ll,int rr)
    {
    	_rt=++o;
    	if(ll==rr){s[_rt]=s[pre_rt]+1;return;}
    	int mid=ll+rr>>1;
    	l[_rt]=l[pre_rt];r[_rt]=r[pre_rt];
    	if(p<=mid)update(l[_rt],l[pre_rt],p,ll,mid);
    	else update(r[_rt],r[pre_rt],p,mid+1,rr);
    	s[_rt]=s[l[_rt]]+s[r[_rt]];
    }
    int query(int rt1,int rt2,int ll,int rr,int kk)
    {
    	if(s[rt2]-s[rt1]<kk)return -1;
    	if(ll==rr)return ll;
    	int rcnt=s[r[rt2]]-s[r[rt1]],mid=ll+rr>>1;
    	if(kk>rcnt)return query(l[rt1],l[rt2],ll,mid,kk-rcnt);
    	else return query(r[rt1],r[rt2],mid+1,rr,kk);
    }
    int main()
    {
    	N=read();M=read();Q=read();T=read();
    	for(int i=1;i<=N;++i)H[i]=read();
    	smer();
    	for(int i=1;i<=M;++i)
    	{
    		int aa=read(),bb=read(),cc=read();
    		e[i].fr=aa;e[i].to=bb;e[i].w=cc;
    	}
    	kruskal();
    	new_H.push_back(0);
    	for(int i=1;i<=N*2-1;++i)
    		if(fd(i)==i)dfs(i,1,0);
    	for(int i=1;i<new_H.size();++i)nH[i]=_H[new_H[i]].num;
    	for(int i=1;i<=N;++i)
    		update(rt[i],rt[i-1],nH[i],1,N);
    	int lastans=0;
    	while(Q--)
    	{
    		int vv=read(),xx=read(),kk=read(),ll=0,rr=0;
    		if(T)vv^=lastans,xx^=lastans,kk^=lastans;
    		get_interval(vv,xx,ll,rr);
    		int ans=query(rt[ll-1],rt[rr],1,N,kk);
    		if(ans==-1)puts("-1"),lastans=0;
    		else printf("%d
    ",B[ans]),lastans=B[ans];
    	}
    	return 0;
    }
    

    T3:

    平面直角坐标系内给出n个点,求一个纵坐标已给出的点使得它到那n个点的距离之和最小
    (n<=10^5)
    题目链接

    solution:

    设出距离之和函数f(x),而后对其求导得到g(x),易知g(x)单调递增(其实是不会证明)
    然后二分求得其零点,带入原函数即可
    注意:精度问题以及求导不要求错了

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int n;
    double k,x[N],y[N],z[N],w[N];
    inline bool ck(double p)
    {
    	double num=0.0;
    	for(int i=1;i<=n;++i)
    		num+=100*(p*2-z[i])/sqrt(p*p-z[i]*p+w[i]);
    	return num>0;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)scanf("%lf%lf",&x[i],&y[i]);
    	scanf("%lf",&k);
    	for(int i=1;i<=n;++i)
    	{
    		z[i]=x[i]*2.0;
    		w[i]=(y[i]-k)*(y[i]-k)+x[i]*x[i];
    	}
    	double l=-1.0e9,r=1.0e9;
    	for(int i=1;i<=150;++i)
    	{
    		double mid=(l+r)/2.0;
    		if(ck(mid)) r=mid;
    		else l=mid;
    	}
    	long double ans=0.0;
    	for(int i=1;i<=n;++i)
    		ans+=sqrt((x[i]-r)*(x[i]-r)+(y[i]-k)*(y[i]-k));
    	cout<<fixed<<setprecision(0)<<ans;
    	return 0;
    }
    
  • 相关阅读:
    置换群
    背包问题
    并查集
    链式前向星
    一个简单的金额平均分配函数(C#版)
    EasyUI ComboGrid的绑定,上下键和回车事件,输入条件查询
    Oracle表解锁语句
    如何将两个json合并成一个
    textbox只能输入数字或中文的常用正则表达式和验证方法
    C#注册表的读,写,删除,查找
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13539100.html
Copyright © 2011-2022 走看看