USACO18FEB Platinum

SlingShot 求数轴上从x到y的最短路( 边长为1),有若干个从xi到yi长度为ti的传送门,每次只能选择其中一个使用。

即求min(|x-y|,min{|a-x|+|b-y|+c}),拆开绝对值,根据相对位置分开讨论,转换成二维数点问题。

MLE的主席树版本:

 1 #include<bits/stdc++.h>
 2 #define P pair<ll,ll>
 3 #define fir first
 4 #define sec second
 5 using namespace std;
 6 typedef long long ll;
 7 int read()
 8 {
 9     int x=0;char ch=getchar();
10     while (ch<'0'||ch>'9') ch=getchar();
11     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
12     return x;
13 }
14 const int N=1e9,T=6e6,M=1e5+5;
15 const ll inf=1ll<<60;
16 P Min[T];
17 int ls[T],rs[T],A[M],x,y,sc,n,rt0[M],rt1[M],m;
18 struct node{ll a,b,c;}p[M];
19 bool cmp(const node &A,const node &B) {return A.a<B.a;}
20 P fmin(P a,P b){
21     return P(min(a.fir,b.fir),min(a.sec,b.sec));
22 };
23 void ins(int &k,int pk,int l,int r,int x,P y)
24 {
25     k=++sc;ls[k]=ls[pk];rs[k]=rs[pk];Min[k]=Min[pk];
26     if (l==r) {Min[k]=fmin(Min[k],y);return;}
27     int mid=(l+r)>>1;
28     if (x<=mid) ins(ls[k],ls[pk],l,mid,x,y);
29     else ins(rs[k],rs[pk],mid+1,r,x,y);
30     Min[k]=fmin(Min[ls[k]],Min[rs[k]]);
31 }
32 P qry(int k,int l,int r,int L,int R)
33 {
34     if (!k) return P(inf,inf);
35     if (L<=l&&r<=R) return Min[k];
36     int mid=(l+r)>>1;P mn=P(inf,inf);
37     if (L<=mid) mn=fmin(mn,qry(ls[k],l,mid,L,R));
38     if (R>mid) mn=fmin(mn,qry(rs[k],mid+1,r,L,R));
39     return mn;
40 }
41 int main()
42 {
43     n=read();m=read();Min[0]=P(inf,inf);
44     for (int i=1;i<=n;i++)
45       p[i].a=read(),p[i].b=read(),p[i].c=read(),A[i]=p[i].a;
46     sort(p+1,p+n+1,cmp);
47     sort(A+1,A+n+1);//寻址数组 
48     for (int i=n;i>=1;i--)
49         ins(rt0[i],rt0[i+1],0,N,p[i].b,P(p[i].a-p[i].b+p[i].c,p[i].a+p[i].b+p[i].c));
50     for (int i=1;i<=n;i++)
51         ins(rt1[i],rt1[i-1],0,N,p[i].b,P(-p[i].a-p[i].b+p[i].c,-p[i].a+p[i].b+p[i].c));
52     while (m--)
53     {
54         x=read();y=read();
55         ll ans=abs(x-y);
56         int k=upper_bound(A+1,A+n+1,x)-A-1; 
57         ans=min(ans,qry(rt0[k+1],1,N,1,y).fir-x+y);
58         ans=min(ans,qry(rt1[k],1,N,1,y).fir+x+y);
59         ans=min(ans,qry(rt0[k+1],1,N,y,N).sec-x-y);
60         ans=min(ans,qry(rt1[k],1,N,y,N).sec+x-y);
61         printf("%lld
",ans);
62     }
63     return 0;
64 }

正常二维数点的树状数组版本(AC):

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int read()
 5 {
 6     int x=0;char ch=getchar();
 7     while (ch<'0'||ch>'9') ch=getchar();
 8     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
 9     return x;
10 }
11 const int M=1e5+5;
12 const ll inf=1ll<<60;
13 int A[M],n,m,tot,t,B[M*2]; ll ans[M],bit[M*2];
14 vector<int> vec1[M],vec2[M];
15 struct node{ll a,b,c,d;}p[M],q[M];
16 bool cmp(const node &A,const node &B) {return A.a<B.a;}
17 int lowbit(int x) {return x&(-x);}
18 void add1(int x,ll y){while (x<=tot) bit[x]=min(bit[x],y),x+=lowbit(x);}//前缀最小值 
19 ll qry1(int x){ll res=inf;while (x) res=min(res,bit[x]),x-=lowbit(x);return res;}
20 void add2(int x,ll y){while (x) bit[x]=min(bit[x],y),x-=lowbit(x);}//后缀最小值 
21 ll qry2(int x){ll res=inf;while (x<=tot) res=min(res,bit[x]),x+=lowbit(x);return res;}
22 void init(){for (int i=1;i<=tot;i++) bit[i]=inf;}
23 int main()
24 {
25     n=read();m=read();
26     for (int i=1;i<=n;i++)
27       p[i].a=read(),p[i].b=B[++tot]=read(),p[i].c=read(),A[i]=p[i].a;
28     sort(p+1,p+n+1,cmp);sort(A+1,A+n+1);//寻址数组 
29     for (int i=1;i<=m;i++) 
30     {
31         q[i].a=read(),q[i].b=B[++tot]=read();ans[i]=abs(q[i].a-q[i].b);
32         int k=upper_bound(A+1,A+n+1,q[i].a)-A-1; 
33         vec1[k+1].push_back(i);
34         vec2[k].push_back(i);
35     }
36     sort(B+1,B+tot+1);tot=unique(B+1,B+tot+1)-B-1;
37     for (int i=1;i<=n;i++) p[i].d=lower_bound(B+1,B+tot+1,p[i].b)-B;
38     for (int i=1;i<=m;i++) q[i].d=lower_bound(B+1,B+tot+1,q[i].b)-B;
39     init();
40     for (int i=n;i>=1;i--)
41     {
42         add1(p[i].d,p[i].a-p[i].b+p[i].c);
43         for (int j=0;j<vec1[i].size();j++)
44           t=vec1[i][j],ans[t]=min(ans[t],qry1(q[t].d)-q[t].a+q[t].b);
45     }
46     init();
47     for (int i=n;i>=1;i--)
48     {
49         add2(p[i].d,p[i].a+p[i].b+p[i].c);
50         for (int j=0;j<vec1[i].size();j++)
51           t=vec1[i][j],ans[t]=min(ans[t],qry2(q[t].d)-q[t].a-q[t].b);
52     }
53     init();
54     for (int i=1;i<=n;i++)
55     {
56         add1(p[i].d,-p[i].a-p[i].b+p[i].c);
57         for (int j=0;j<vec2[i].size();j++)
58           t=vec2[i][j],ans[t]=min(ans[t],qry1(q[t].d)+q[t].a+q[t].b);
59     }
60     init();
61     for (int i=1;i<=n;i++)
62     {
63         add2(p[i].d,-p[i].a+p[i].b+p[i].c);
64         for (int j=0;j<vec2[i].size();j++)
65           t=vec2[i][j],ans[t]=min(ans[t],qry2(q[t].d)+q[t].a-q[t].b);
66     }
67     for (int i=1;i<=m;i++) printf("%lld
",ans[i]);
68     return 0;
69 }

Newbarn 加点x,询问x在树上能走的最远距离

最远距离一定会走到直径端点。维护每棵树的直径(维护一条就够了)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=100005;
 4 int q,x,dep[N],fa[N][25],id,bel[N],sc,Max,u[N],v[N],tmp;
 5 char s[5];
 6 int lca(int x,int y)
 7 {
 8     if (dep[x]<dep[y]) swap(x,y);
 9     int del=dep[x]-dep[y];
10     for (int i=20;i>=0;i--)
11       if (del&(1<<i)) x=fa[x][i];
12     if (x==y) return x;
13     for (int i=20;i>=0;i--)
14       if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
15     return fa[x][0];
16 }
17 int dis(int x,int y) {return dep[x]+dep[y]-2*dep[lca(x,y)];}
18 int main()
19 {
20     scanf("%d",&q);
21     while (q--)
22     {
23         scanf("%s%d",s,&x);
24         if (s[0]=='B')
25         {
26             id++;
27             if (x!=-1) 
28             {
29                 dep[id]=dep[x]+1,fa[id][0]=x; bel[id]=bel[x];
30                 for (int j=1;j<=20;j++)
31                   fa[id][j]=fa[fa[id][j-1]][j-1];
32                 Max=dis(u[bel[id]],v[bel[id]]);
33                 if (tmp=dis(id,u[bel[id]]),tmp>Max) Max=tmp,v[bel[id]]=id;
34                 if (tmp=dis(id,v[bel[id]]),tmp>Max) Max=tmp,u[bel[id]]=id;
35             }else bel[id]=++sc,u[sc]=v[sc]=id;
36         }else printf("%d
",max(dis(x,u[bel[x]]),dis(x,v[bel[x]])));
37     }
38     return 0;
39 }

Cow Gymnasts 求有多少个数组A任意位i都满足A[i]=sigma[A[i-j+1]>=j](i-j+1<=0时从N开始往下)?(1<=A[i]<=N)

关键点在发现循环节。大胆从最小位置x入手,设其值为m,则满足y=x(mod gcd(N,m)的位置y的值都为m。

同样也可以归纳证明,所有位置的值都<=m+1。(注意一个循环节中有一个m+1,那么就不会出现m)

枚举m,$Ans=sum_{m=1}^{n-1}(2^{gcd(n,m)}-1)+1$。m=n的情况只有可能全是m,故加1。

把gcd提出来,$Ans=sum_{d|n}2^d*varphi(N/d)-N+2-2^N$。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int mod=1e9+7;
 5 #define P pair<ll,int>
 6 ll n,ans,sum;
 7 map<ll,ll> Phi;
 8 vector<P> vec;
 9 ll ksm(ll x,ll y) {
10     ll res=1;
11     while (y) {if (y&1) res=res*x%mod; x=x*x%mod;y>>=1;}
12     return res;
13 }
14 void dvd(ll x)
15 {
16     for (int i=2;i<=sqrt(x);i++)
17       if (x%i==0)
18       {
19           sum*=i-1;int cnt=1;x/=i;
20           while (x%i==0) x/=i,cnt++,sum*=i;
21           vec.push_back(P(i,cnt));
22       }
23     if (x!=1) vec.push_back(P(x,1));
24 }
25 void dfs(ll x,int d,ll phi)
26 {
27     if (d==vec.size()) {Phi[x]=phi;return;}
28     dfs(x,d+1,phi);
29     ll t=vec[d].first,sum=t-1;
30     for (int i=1;i<=vec[d].second;i++)
31     {
32         x*=t;
33         dfs(x,d+1,phi*sum);
34         sum*=t;
35     }
36 }
37 int main()
38 {
39     scanf("%lld",&n);
40     if (n==1) return puts("1"),0;
41     sum=1;dvd(n);
42     dfs(1,0,1);ans=((2-n-ksm(2,n))%mod+mod)%mod;
43     for (int i=1;i<=sqrt(n);i++)
44       if (n%i==0){
45           ans+=ksm(2,i)*Phi[n/i]%mod; ans%=mod;
46           if ((ll)i*i!=n) ans+=ksm(2,n/i)*Phi[i]%mod,ans%=mod;
47       }
48     printf("%lld
",ans);
49     return 0;
50 }
原文地址:https://www.cnblogs.com/Scx117/p/9123933.html