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;
    }
    
  • 相关阅读:
    HDU2059(龟兔赛跑)
    pat 1012 The Best Rank
    pat 1010 Radix
    pat 1007 Maximum Subsequence Sum
    pat 1005 Sign In and Sign Out
    pat 1005 Spell It Right
    pat 1004 Counting Leaves
    1003 Emergency
    第7章 输入/输出系统
    第六章 总线
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13539100.html
Copyright © 2011-2022 走看看