noip模拟67
A. 数据恢复
又一次徘徊于正解的边缘.
什么都可以想到,但偏是实现的方法不对.
本来可以直接用 \(set\) 的东西结果非要打线段树.
别的东西推推性质就行了.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll res=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return cit?res:-res;
}
} using namespace BSS;
const ll N=3e5+21;
ll m,n,ans,ts;
ll head[N],fa[N],tn[N],to[N],in[N];
multiset<pair<lf,ll> > s;
struct I { ll a,b; lf c; } p[N],bin[N];
ll find(ll x){ return x==fa[x] ? x : fa[x]=find(fa[x]); }
inline void getc(ll x){ p[x].c=1.0*p[x].a/(1.0*p[x].b); }
inline void merge(ll x,ll y){
ans+=p[y].b*p[x].a;
p[y].a+=p[x].a,p[x].a=0;
p[y].b+=p[x].b,p[x].b=0;
getc(y),fa[find(x)]=find(y);
}
signed main(){
File(data);
n=read(); ll u,v,sum=0;
for(int i=2;i<=n;i++) to[i]=read();
for(int i=1;i<=n;i++){
p[i].a=read(),p[i].b=read(),getc(i);
s.insert(mp(p[i].c,i)),in[i]=1,fa[i]=i;
}
while(s.size()){
auto it=s.begin();
u=it->second,v=find(to[u]);
s.erase(s.begin()),in[u]=0;
if(!to[u]) continue;
if(in[v]){
s.erase(s.find(mp(p[v].c,v)));
merge(u,v);
s.insert(mp(p[v].c,v));
}
else{
merge(u,find(v));
}
}
printf("%lld\n",ans);
exit(0);
}
B. 下落的小球
感觉这个题目比 \(T1\) 更可做.
数学题,可以看成两个可重集排列来做.
第一个可重集排列:
考虑每个子树除了要落下自己的子树上的点之外,还要落下祖先上的点.
但是落到每棵子树上的祖先上的点的个数是固定的,只是落到不同子树的顺序不同.
所以这个时候可以给顺序写一个可重集排列.
第二个可重集排列:
每个子树在降落完祖先上的点之后,再去分别降落自己子树上面的点.
发现仍然只需要考虑各个子树的降落顺序.
再写一个可重集排列就行了.
最后两个方案数乘起来就是答案.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long
#define ull unsigned ll
#define lf long double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll res=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return cit?res:-res;
}
} using namespace BSS;
const ll N=1e6+21,mod=1e9+7;
ll m,n,ts,ans;
ll head[N],req[N],frc[N],siz[N],inv[N];
struct I { ll u,v,nxt; } e[N];
inline void add(ll u,ll v){
e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u];
head[u]=ts;
}
inline ll ksm(ll a,ll b,ll c){
ll res=1; a%=c;
for(;b;b>>=1,a=a*a%c) if(b&1) res=res*a%c;
return res%c;
}
void dfs(ll u){
siz[u]=1; if(!head[u]) return ;
for(int i=head[u];i;i=e[i].nxt){
dfs(e[i].v),siz[u]+=siz[e[i].v];
}
for(int i=head[u];i;i=e[i].nxt){
ans=ans*inv[siz[e[i].v]]%mod*inv[req[e[i].v]-siz[e[i].v]]%mod;
req[u]+=req[e[i].v];
}
// if(req[u]<siz[u]) puts("0"),exit(0);
ans=ans*frc[siz[u]-1]%mod*frc[req[u]-siz[u]+1]%mod;
}
signed main(){
File(ball);
n=read(),frc[0]=1,ans=1; ll u;
for(int i=2;i<=n;i++) u=read(),add(u,i);
for(int i=1;i<=n;i++) req[i]=read(),frc[i]=frc[i-1]*i%mod;
inv[n]=ksm(frc[n],mod-2,mod);
for(int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
dfs(1),printf("%lld\n",ans),exit(0);
}
C. 消失的运算符
D. 古老的序列问题
解决这种形如 \(\sum\limits_l \sum\limits_r\) 的序列问题时,有时候分治是一个比较不错的入手方向.
感觉这题比较套路,比如固定左端点、然后求右端点,离线处理然后排序做单调性等等.
基本就这些.
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
for(;!isdigit(ch);ch=getchar()) cit=(ch=='-');
for(;isdigit(ch);ch=getchar()) w=(w<<3)+(w<<1)+(ch^48);
return cit?(-w):w;
};
} using namespace BSS;
const int N=1e5+21,inf=1e15,mod=1e9+7;
#define ls (x<<1)
#define rs (x<<1|1)
int m,n,ops;
int mx[N],mn[N],mul[N],val[N],ans[N],org[N],f[N<<2];
struct I {
int l,r,id;
I(){}
I(int l_,int r_,int id_) : l(l_),r(r_),id(id_) {}
};
vector<I> vec[N<<2];
struct Seg_Tree{
struct I { int w,sum,lzy; } tr[N<<2];
inline void getval(int x,int w){
tr[x].sum=(tr[x].sum+tr[x].w*w%mod)%mod,tr[x].lzy=(tr[x].lzy+w)%mod;
}
inline void pushup(int x){
tr[x].sum=(tr[ls].sum+tr[rs].sum)%mod;
}
inline void spread(int x){
int &lzy=tr[x].lzy; if(!lzy) return ;
getval(ls,lzy),getval(rs,lzy),lzy=0;
}
inline void build(int x,int l,int r,int a[]){
tr[x].w=0,tr[x].sum=0,tr[x].lzy=0;
if(l==r) return tr[x].w=a[l],void();
int mid=(l+r)>>1;
build(ls,l,mid,a),build(rs,mid+1,r,a);
tr[x].w=(tr[ls].w+tr[rs].w)%mod;
};
inline void upd(int x,int l,int r,int ql,int qr,int w){
if(ql>qr) return ;
if(l>=ql and r<=qr) return getval(x,w),void();
int mid=(l+r)>>1; spread(x);
if(ql<=mid) upd(ls,l,mid,ql,qr,w);
if(qr>mid) upd(rs,mid+1,r,ql,qr,w);
pushup(x);
}
inline int qry(int x,int l,int r,int ql,int qr){
if(ql>qr) return 0;
if(l>=ql and r<=qr) return tr[x].sum;
int mid=(l+r)>>1,res=0; spread(x);
if(ql<=mid) res+=qry(ls,l,mid,ql,qr);
if(qr>mid) res+=qry(rs,mid+1,r,ql,qr);
return pushup(x),res%mod;
}
}A,B,C,D;
auto query(int l,int r,int ql,int qr)->int{
// cout<<"query:"<<l<<' '<<r<<' '<<ql<<' '<<qr<<endl;
// cout<<A.qry(1,l,r,ql,qr)<<' '<<B.qry(1,l,r,ql,qr)<<' '<<C.qry(1,l,r,ql,qr)<<' '<<D.qry(1,l,r,ql,qr)<<endl;
return (A.qry(1,l,r,ql,qr)+B.qry(1,l,r,ql,qr)+C.qry(1,l,r,ql,qr)+D.qry(1,l,r,ql,qr))%mod;
};
inline void solve(int x,int l,int r){
if(l==r){
f[x]=val[l]*val[l]%mod;
for(auto i : vec[x]) ans[i.id]=(ans[i.id]+f[x])%mod;
return void();
}
int mid=(l+r)>>1,p1=mid,p2=mid,nowmin=inf,nowmax=0;
mx[mid]=0,mn[mid]=inf,vec[0].clear();
for(auto i : vec[x]) if((i.l^l or i.r^r) and i.l<=mid and i.r>mid) vec[0].pb(i);
sort(vec[0].begin(),vec[0].end(),[](I i,I j){ return i.l>j.l; });
for(int i=mid+1;i<=r;i++){
mx[i]=max(mx[i-1],val[i]),mn[i]=min(mn[i-1],val[i]);
mul[i]=mx[i]*mn[i]%mod;
}
A.build(1,mid+1,r,org),B.build(1,mid+1,r,mul);
C.build(1,mid+1,r,mx),D.build(1,mid+1,r,mn);
for(int i=mid,j=0,lmj=vec[0].size();i>=l;i--){
nowmax=max(nowmax,val[i]),nowmin=min(nowmin,val[i]);
while(p1<r and mx[p1+1]<nowmax) p1++;
while(p2<r and mn[p2+1]>nowmin) p2++;
// cout<<nowmax<<' '<<nowmin<<endl;
A.upd(1,mid+1,r,mid+1,min(p1,p2),nowmax*nowmin%mod);
B.upd(1,mid+1,r,max(p1,p2)+1,r,1);
if(p1<p2) C.upd(1,mid+1,r,p1+1,p2,nowmin);
if(p1>p2) D.upd(1,mid+1,r,p2+1,p1,nowmax);
// cout<<vec[0][j].l<<" "<<i<<" skr\n";
while(j<lmj and vec[0][j].l==i){
// cout<<i<<' '<<lmj<<" "<<j<<' '<<vec[0][j].r<<' '<<vec[0][j].id<<' '<<query(mid+1,r,i,vec[0][j].r)<<endl;
ans[vec[0][j].id]=(ans[vec[0][j].id]+query(mid+1,r,i,vec[0][j].r))%mod,j++;
}
}
for(auto i : vec[x]){
if(i.l==l and i.r==r) continue;
if(i.r<=mid) vec[ls].pb(i);
else if(i.l>mid) vec[rs].pb(i);
else vec[ls].pb(I(i.l,mid,i.id)),vec[rs].pb(I(mid+1,i.r,i.id));
}
f[x]=query(mid+1,r,mid+1,r);
// cout<<"L and R:"<<l<<" "<<r<<" "<<f[x]<<endl;
solve(ls,l,mid),solve(rs,mid+1,r);
f[x]=(f[x]+f[ls]+f[rs])%mod;
// cout<<"L and R:"<<l<<' '<<r<<' '<<f[x]<<' '<<f[ls]<<" "<<f[rs]<<endl;
for(auto i : vec[x]){
if((i.l^l) or (i.r^r)) continue;
ans[i.id]=(ans[i.id]+f[x])%mod;
}
}
signed main(){
File(sequence);
n=read(),ops=read(); int l,r;
for(int i=1;i<=n;i++) val[i]=read(),org[i]=1;
for(int i=1;i<=ops;i++) l=read(),r=read(),vec[1].pb(I(l,r,i));
solve(1,1,n);
for(int i=1;i<=ops;i++) printf("%lld\n",ans[i]%mod);
exit(0);
}