T1——diamond(3923)
Description:
有一个
n
∗
n
n*n
n∗n的矩形,每个格
(
i
,
j
)
(i,j)
(i,j)上的权值是数
i
+
j
i+j
i+j的奇数码之和与偶数码之和之差的绝对值.
e
g
:
3241
=
∣
(
2
+
4
)
−
(
1
+
3
)
∣
eg: 3241=|(2+4)-(1+3)|
eg:3241=∣(2+4)−(1+3)∣.这样有
q
q
q组询问.
n
,
q
≤
1
0
6
n , q \le 10^6
n,q≤106
Solution:
- 首先观察一下这个矩形的数 i + j i+j i+j的分布,不难发现数 2 2 2$n+1$出现了$i-1$次,而$n+2$ n + n n+n n+n的出现次数也是与之对称的.
- 这样的话,就可以先预处理出每个数的权值以及权值前缀和和后缀和.
- 那么对于询问就是前缀和、后缀和做一下差即可.
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;int f=1;
while((c=getchar())<48)if(c=='-')f=-1;
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
x*=f;
}
#define N 1000005
int Abs(int x){return x>0?x:-x;}
ll num[N<<1],sum[N<<1],f1[N<<1],f2[N<<1];
int calc(int x){
int sum1=0,sum2=0,y;
for(int i=1;x;x/=10,++i){
y=x%10;
if(y&1)sum1+=y;
else sum2+=y;
}
return Abs(sum1-sum2);
}
void Init(){
SREP(i,2,N<<1)num[i]=calc(i);
SREP(i,2,N<<1)sum[i]=sum[i-1]+num[i];
SREP(i,2,N<<1)f1[i]=f1[i-1]+num[i]*(i-1);
DREP(i,(N<<1)-1,1)f2[i]=f2[i+1]+num[i]*((N<<1)-i+1);
}
int main(){
// freopen("diamond.in","r",stdin);
// freopen("diamond.out","w",stdout);
Init();
int cas,n;Rd(cas);
while(cas--) Rd(n),printf("%lld\n",f1[n]+f2[n+1]-f2[2*n+1]-(sum[2*n]-sum[n])*((N<<1)-(2*n)));
return 0;
}
T1——biscuit(3924)
Description:
有一个长度为
n
n
n的序列
A
A
A,对于
A
i
≤
x
A_i \le x
Ai≤x,有
q
q
q个区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],求这个
q
q
q个区间的最小值的最大值得期望.
n
,
x
,
q
≤
2000
n , x , q \le 2000
n,x,q≤2000
Solution:
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,dp,t)for(int i=(dp),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,dp,t)for(int i=(dp),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,dp,t)for(int i=(dp),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;int dp=1;
while((c=getchar())<48)if(c=='-')dp=-1;
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
x*=dp;
}
#define N 2002
#define mod 1000000007
int n,x,q;
struct node{
int l,r;
bool operator<(const node &_)const{
return l==_.l?r>_.r:l<_.l;
}
}Q[N];
void Add(ll &x,ll y){
x+=y;
if(x>=mod)x-=mod;
else if(x<0)x+=mod;
}
ll Pow(ll a,ll b){
ll x=1;
while(b){
if(b&1)x=x*a%mod;
a=a*a%mod,b>>=1;
}
return x;
}
struct p20{
int A[20];
ll sum,ans;
void solve(){
REP(i,1,n) A[i]=1;
while(1){
int Mx=0;
REP(i,1,q){
int Mn=A[Q[i].r];
SREP(j,Q[i].l,Q[i].r) chkmin(Mn,A[j]);
chkmax(Mx,Mn);
}
Add(ans,Mx);
Add(sum,1);
int p=1;
while(p<=n && A[p]==x){
A[p]=1;
++p;
}
if(p>n)break;
++A[p];
}
printf("%lld\n",ans*Pow(sum,mod-2)%mod);
}
}p1;
struct p40{
ll ans;
void solve(){
int m=Q[1].r-Q[1].l+1;
REP(i,1,x) Add(ans,(Pow(x-i+1,m)-Pow(x-i,m))*i%mod);
printf("%lld\n",(ans*Pow(Pow(x,m),mod-2)%mod+mod)%mod);
}
}p2;
struct p80{
ll ans;
ll inv[N],dp[N];
int stk[N],top;
int nxt[N],pre[N];
int L,R;
void Init(){
sort(Q+1,Q+1+q);
REP(i,1,q){
while(Q[i].r<=Q[stk[top]].r)--top;
stk[++top]=i;
}
q=top;
REP(i,1,q)Q[i]=Q[stk[i]];
L=1,R=0;
REP(i,1,n){
while(R<q && Q[R+1].l<=i)++R;
while(L<=q && Q[L].r<i)++L;
pre[i]=L,nxt[i]=R;
}
}
void solve(){
Init();
REP(i,1,x){
int j=0;
ll s=1,t=1;
inv[0]=1;
dp[0]=1;
ll p=((ll)(i-1+mod)%mod*Pow(x,mod-2))%mod;
ll pc=(1-p+mod)%mod;
inv[1]=Pow(pc,mod-2);
REP(k,2,n) inv[k]=inv[k-1]*inv[1]%mod;
REP(k,1,n){
while(j<k && nxt[j]<pre[k]-1)Add(s,-dp[j]*inv[j]%mod+mod),j++;
dp[k]=s*t%mod*p%mod;
t=t*pc%mod;
Add(s,dp[k]*inv[k]%mod);
}
s=0;
t=1;
for(int k=n;k>=1 && nxt[k]==q;k--) Add(s,dp[k]*t%mod),t=t*pc%mod;
Add(ans,(1-s+mod)%mod);
}
printf("%lld\n",ans);
}
}p3;
int main(){
// freopen("biscuit.in","r",stdin);
// freopen("biscuit.out","w",stdout);
Rd(n),Rd(x),Rd(q);
REP(i,1,q) Rd(Q[i].l),Rd(Q[i].r);
if(q==1)p2.solve();
else if(n<=6 && x<=6 && q<=6)p1.solve();
else p3.solve();
return 0;
}
T3——plague(3925)
Description:
有一棵
n
n
n个节点的树,现在有一种病毒入侵.
e
g
:
eg:
eg:点
x
x
x被传播病毒,那么该点会被感染,而二次感染点
x
x
x,会将病毒向下传播.
有
q
q
q个操作:
- 将点 x x x传播病毒.
- 净化以 x x x为根的子树.
- 询问点 x x x是否被感染.
n ≤ 1 0 6 , q ≤ 2 ∗ 1 0 6 n \le 10^6 , q \le 2*10^6 n≤106,q≤2∗106
Solution:
- 次题乍一看这个传播好像有点麻烦,还需要标记一下…
- 但仔细想想这应该是一道比较正常的传统数据结构题了…(树剖+线段树)
- 那么我们先分析一下操作的实际意义:
- 操作 1 1 1、 2 2 2:区间修改,操作 3 3 3:单点查询.(而且这里比较特殊,树剖到 1 1 1即可)
- 那么问题还是对本题感染操作的理解,我们可以将初始值为 − 1 -1 −1,那么每次操作 1 1 1为+1,那么询问即为是否 ≥ 0 \ge 0 ≥0.
- 那么就是实现难度要注意的细节问题了.
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
x=0;char c;int f=1;
while((c=getchar())<48)if(c=='-')f=-1;
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
x*=f;
}
#define N 100002
int n,m;
int qwq,head[N];
struct edge{
int to,nxt;
}E[N<<1];
void addedge(int x,int y){E[qwq]=(edge){y,head[x]};head[x]=qwq++;}
#define EREP(x) for(int i=head[x];~i;i=E[i].nxt)
int fa[N],sz[N],dep[N],son[N],top[N];
int Lt[N],Rt[N],sgID[N],tim;
struct p50{
int mark[N];
void dfs(int x){
Lt[x]=++tim;
sgID[tim]=x;
EREP(x){
int y=E[i].to;
if(y==fa[x])continue;
dfs(y);
}
Rt[x]=tim;
}
void go(int x){
// printf("x=%d\n",x);
EREP(x){
int y=E[i].to;
if(y==fa[x])continue;
++mark[y];
if(mark[y]>1) go(y);
}
}
void solve(){
dfs(1);
int op,x;
while(m--){
Rd(op),Rd(x);
if(op==1) {
++mark[x];
// if(mark[x]>1) EREP(x) if(E[i].to!=fa[x]) ++mark[E[i].to],go(E[i].to);
if(mark[x]>1) go(x);
}
if(op==2) REP(i,Lt[x],Rt[x]) mark[sgID[i]]=0;
if(op==3) /*printf("cnt=%d ",mark[x]),*/puts(mark[x]?"Yes":"No");
}
}
}p1;
struct p100{
void dfs1(int x){
sz[x]=1;
son[x]=0;
dep[x]=dep[fa[x]]+1;
EREP(x){
int y=E[i].to;
if(y==fa[x])continue;
dfs1(y);
sz[x]+=sz[y];
if(sz[son[x]]<sz[y])son[x]=y;
}
}
void dfs2(int x,int tp){
Lt[x]=++tim;
sgID[tim]=x;
top[x]=tp;
if(son[x])dfs2(son[x],tp);
EREP(x){
int y=E[i].to;
if(y==fa[x] || y==son[x])continue;
dfs2(y,y);
}
Rt[x]=tim;
}
struct Tree{
#define lson L,mid,p<<1
#define rson mid+1,R,p<<1|1
#define family tree[p],tree[p<<1],tree[p<<1|1]
struct node{
int L,R;
int sum,mx;
bool add;
}tree[N<<2];
void Change(node &A){
A.add=1;
A.mx=-1;
A.sum=-(A.R-A.L+1);
}
void Down(node &A,node &L,node &R){
if(!A.add)return;
Change(L),Change(R);
A.add=0;
}
void Up(node &A,node L,node R){
chkmax(A.mx=R.mx,L.mx+R.sum);
A.sum=L.sum+R.sum;
}
void build(int L,int R,int p){
tree[p].L=L,tree[p].R=R;
if(L==R){
tree[p].mx=tree[p].sum=-1;
return;
}
int mid=(L+R)>>1;
build(lson),build(rson);
Up(family);
}
void update1(int L,int R,int p){
if(tree[p].L==L && tree[p].R==R){
Change(tree[p]);
return;
}
Down(family);
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)update1(L,R,p<<1);
else if(L>mid)update1(L,R,p<<1|1);
else update1(lson),update1(rson);
Up(family);
}
void update2(int x,int p,int v){
if(tree[p].L==tree[p].R){
tree[p].mx+=v;
tree[p].sum+=v;
return;
}
Down(family);
int mid=(tree[p].L+tree[p].R)>>1;
if(x<=mid)update2(x,p<<1,v);
else update2(x,p<<1|1,v);
Up(family);
}
node query(int L,int R,int p){
if(tree[p].L==L && tree[p].R==R)return tree[p];
Down(family);
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)return query(L,R,p<<1);
else if(L>mid)return query(L,R,p<<1|1);
else {
node res;
Up(res,query(lson),query(rson));
return res;
}
}
node find(int x){
node ans=query(Lt[top[x]],Lt[x],1);
x=fa[top[x]];
while(x){
node res=query(Lt[top[x]],Lt[x],1);
x=fa[top[x]];
Up(ans,res,ans);
}
return ans;
}
}T;
void solve(){
dfs1(1);
dfs2(1,1);
T.build(1,n,1);
int op,x;
while(m--){
Rd(op),Rd(x);
if(op==1) T.update2(Lt[x],1,1);
if(op==2) T.update1(Lt[x],Rt[x],1),T.update2(Lt[x],1,-T.find(x).mx-1);
if(op==3) puts(T.find(x).mx>-1?"Yes":"No");
}
}
}p3;
int main(){
// freopen("plague.in","r",stdin);
// freopen("plague.out","w",stdout);
mcl(head,-1);
Rd(n),Rd(m);
REP(i,2,n){
Rd(fa[i]);
addedge(i,fa[i]);
addedge(fa[i],i);
}
if(n<=3000 && m<=3000)p1.solve();
else p3.solve();
return 0;
}
总结: