SDOI2017 Round1解题报告

来源:互联网 发布:网络投票公司加盟 编辑:程序博客网 时间:2024/06/05 19:00

虽然考的很差,很不想去再面对这套题,但是只有直面失败才能走向成功。从新审视这套题,才发现自己存在的问题和差距。

Day 1

T1

这里写图片描述

题解

mobius反演。。。
ni=1mj=1fi[gcd(i,j)]
nk=1fi[k]ni=1mj=1[gcd(i,j)=k]
f(d)=ni=1mj=1[gcd(i,j)=k] ,表示最大公约数为k的数对数
F(d)=ndmd 表示公约数为k的数对数
根据莫比乌斯反演的公式f(d)=d|nμ(nd)F(n)
所以式子可以变成

k=1nfi[k]ni=1μ(i)nkimki
,当时考试的时候就化简到这一步,然后设g(x,y)=ni=1μ(i)xiyi,x=nk,y=mk,直接根号套根号的做,TLE了4组。
但是实际上式子还能进一步的化简,设T=ik
T=1n(d|nfi[d]μ(Td))nTmT

h(T)=d|nfi[d]μ(Td),如果h(T)可以预处理,那么回答询问的时间复杂度就是O(n+m)。发现h(T)的求解与T的约数有关,可以用艾氏筛法O(nlog2n)的求,其中一个logn是快速幂的。
我们预处理出h(T)的前缀积和前缀积的逆元,就可以搞啦。
有一点需要特别注意:a(p1)=1(mod p)  p 是质数,所以所有的指数是对(p1)取模,考试的时候脑残,因为这个原因丢了30分,想想就心疼。。。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 1000000#define LL long long #define p 1000000007#define mod 1000000006using namespace std;int pd[N+3],prime[N+3],n,m,T;LL f[N+3],mu[N+3],inv[N+3],cnt[N+3],fi[N+3];LL quickpow(LL num,LL x){    x=(x%mod+mod)%mod;    LL base=num%p; LL ans=1;    while (x) {        if (x&1) ans=ans*base%p;        x>>=1;        base=base*base%p;    }    return ans;}void init(){    mu[1]=1; fi[0]=0; fi[1]=1; inv[0]=1;    for (int i=2;i<=N;i++) fi[i]=(fi[i-1]+fi[i-2])%p;    for (int i=2;i<=N;i++) {        if (!pd[i]) {            prime[++prime[0]]=i;            mu[i]=-1;        }        for (int j=1;j<=prime[0];j++) {            if (i*prime[j]>N) break;            pd[i*prime[j]]=1;            if (i%prime[j]==0) {                mu[i*prime[j]]=0;                break;            }            mu[i*prime[j]]=-mu[i];        }    }    for (int i=0;i<=N;i++) f[i]=1;    for (int i=1;i<=N;i++) {        for (int j=i,t=1;j<=N;j+=i,t++)          f[j]=f[j]*quickpow(fi[i],mu[t])%p;    }    for (int i=2;i<=N;i++) f[i]=f[i]*f[i-1]%p;    for (int i=1;i<=N;i++) inv[i]=quickpow(f[i],p-2);}int main(){    freopen("product.in","r",stdin);    freopen("product.out","w",stdout);    scanf("%d",&T);    init();    while (T--){        scanf("%d%d",&n,&m);        if (n>m) swap(n,m);        LL ans=1;        for (int i=1,j;i<=n;i=j+1) {            j=min(n/(n/i),m/(m/i));            LL t=(LL)(n/i)*(m/i);            ans=ans*quickpow(f[j]*inv[i-1],t)%p;        }        printf("%I64d\n",ans);    }}



T2

这里写图片描述
这里写图片描述

题解

LCT+线段树
感觉自己对LCT一直有抵触情绪。。。。所以决定好好写这道题的题解。
一条路径的权值为:路径上的颜色种类和。
我们定义f(x),表示x与fa[x]的颜色是否相同,相同为0,不同为1,令 f(1)=1。g(x)表示x到root路径上的f的和。然后考虑怎么维护g(x)。
这里写图片描述
因为是一颗有根树,所以我们不牵扯到换根操作,最初的时候所以的节点都是指向他的父节点的。(儿子认父亲,父亲不认儿子)。lct维护的splay中的信息,一定是一条重链的信息。对于这条链来说,splay中所有节点的颜色都是相同的。
现在我们要将x到root的路径染成一种新的颜色,利用access操作实现对节点的修改。
access中有一个砍重儿子的过程,对于上图中的三号紫点来说,砍掉了四号紫点(不是单独的一个点,而是四号紫点所在的splay),对于四号紫点所在的splay维护的重链的链顶节点(就是三号紫点真正的儿子)来说,他子树中的所有点g值都会增加1。
现在一号蓝点变成了三号紫点的重儿子,那么对应的一号蓝点所在的splay维护的重链的链顶节点子树中所有点的g值都减少1.
根据access的过程假设当前点是三号紫点,那么他与root在一棵splay中,转根后他就是splay的根,fa[x]就是0,不在需要更改任何g的值。我们发现对于1-3号紫点他们的g值在染色过程中是不发生改变的,所以可以用lct科学的维护。
那么g值得改变都是针对子树的,所以我们搞出dfs序,那么每次修改都是修改的一段区间,就变成了线段树的区间修改。
对于操作3,直接进行区间查询即可。
对于操作2,x->y 的答案就是g(x)+g(y)-2*g(lca(x,y))+1,进行三次单点查询。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 400003using namespace std;int point[N],nxt[N],v[N],tr[N],delta[N],l[N],r[N],deep[N],mi[20];int n,m,k,col[N],f[N][20],fa[N],ch[N][3],tot,sz,pos[N],cur[N];void add(int x,int y){    tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;    tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void dfs(int rt){    int x=rt;     while (true) {        if (!deep[x]) {            deep[x]=deep[f[x][0]]+1;             for (int i=1;i<=17;i++) {                if (deep[x]-mi[i]<0) break;                f[x][i]=f[f[x][i-1]][i-1];            }            l[x]=r[x]=++sz; pos[sz]=x; cur[x]=point[x];        }        bool pd=false;        for (int i=cur[x];i;i=nxt[i]) {            cur[x]=nxt[i];            if (v[i]!=f[x][0]) {                f[v[i]][0]=fa[v[i]]=x; x=v[i]; pd=true;                break;            }        }        if (!pd) {            int t=f[x][0];// cout<<t<<endl;            r[t]=max(r[t],r[x]);            if (x==rt)  break;            x=t;        }    }}int lca(int x,int  y){    if (deep[x]<deep[y]) swap(x,y);    int k=deep[x]-deep[y];    for (int i=0;i<=17;i++)     if ((k>>i)&1) x=f[x][i];    if (x==y) return x;    for (int i=17;i>=0;i--)     if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];    return f[x][0];}void update(int now){    tr[now]=max(tr[now<<1],tr[now<<1|1]);}void pushdown(int now){    if (delta[now]) {        tr[now<<1]+=delta[now]; tr[now<<1|1]+=delta[now];        delta[now<<1]+=delta[now]; delta[now<<1|1]+=delta[now];        delta[now]=0;    }}void qjchange(int now,int l,int r,int ll,int rr,int val){    if (ll<=l&&r<=rr) {        tr[now]+=val; delta[now]+=val;        return;    }    int mid=(l+r)/2;     pushdown(now);    if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,val);    if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,val);    update(now);}int find(int now,int l,int r,int x){    if (l==r) return tr[now];    int mid=(l+r)/2;    pushdown(now);    if (x<=mid) return find(now<<1,l,mid,x);    else return find(now<<1|1,mid+1,r,x);}int query(int now,int l,int r,int ll,int rr){    if (ll<=l&&r<=rr) return tr[now];    int mid=(l+r)/2; int ans=0;    pushdown(now);    if (ll<=mid) ans=max(ans,query(now<<1,l,mid,ll,rr));    if (rr>mid) ans=max(ans,query(now<<1|1,mid+1,r,ll,rr));    return ans;}bool isroot(int x){    return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;}int get(int x){    return ch[fa[x]][1]==x;}void rotate(int x){    int y=fa[x]; int z=fa[y]; int which=get(x);    if (!isroot(y)) ch[z][ch[z][1]==y]=x;    fa[x]=z; fa[y]=x; ch[y][which]=ch[x][which^1];    fa[ch[x][which^1]]=y; ch[x][which^1]=y;}void splay(int x){    int y;    while (!isroot(x)){        y=fa[x];        if (!isroot(y)) rotate(get(y)==get(x)?y:x);        rotate(x);    }}int get_root(int x){    while (ch[x][0]) x=ch[x][0];    return x;}void access(int x){    int t=0;    while (x) {        col[x]=k;        splay(x);        int t1=get_root(ch[x][1]);        if (t1) qjchange(1,1,n,l[t1],r[t1],1);        ch[x][1]=t;        int t2=get_root(t);        if (t2) qjchange(1,1,n,l[t2],r[t2],-1);        t=x; x=fa[x];    }}int main(){    freopen("paint.in","r",stdin);    freopen("paint.out","w",stdout);    scanf("%d%d",&n,&m); k=n; mi[0]=1;    for (int i=1;i<=18;i++) mi[i]=mi[i-1]*2;    for (int i=1;i<n;i++) {        int x,y; scanf("%d%d",&x,&y);        add(x,y);    }    dfs(1);    for (int i=1;i<=n;i++) qjchange(1,1,n,l[i],r[i],1);    for (int i=1;i<=m;i++) {        int opt,x,y; scanf("%d%d",&opt,&x);        if (opt==1) k++,access(x);        if (opt==2) {            scanf("%d",&y); int t=lca(x,y);            printf("%d\n",find(1,1,n,l[x])+find(1,1,n,l[y])-2*find(1,1,n,l[t])+1);        }        if (opt==3) printf("%d\n",query(1,1,n,l[x],r[x]));    }}



T3

这里写图片描述

题解

DP+矩阵乘法
至少有一个数是质数的方案数=无限制的方案数-只有质数的方案数
预处理出转移矩阵,直接上矩阵快速幂即可。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 20000003#define M 103#define mod 20170408#define LL long long using namespace std;bool pd[N]; int prime[N],a[M],b[M],n,m,p;struct data{    LL a[M][M];}e,c;void init(){    for (int i=2;i<=m;i++) {        if(!pd[i]) prime[++prime[0]]=i;        for (int j=1;j<=prime[0];j++) {            if (i*prime[j]>m) break;            pd[i*prime[j]]=1;            if (i%prime[j]==0) break;        }    }    for (int i=1;i<=m;i++) a[i%p]++;    for (int i=1;i<=prime[0];i++) b[prime[i]%p]++;    for (int i=0;i<p;i++) b[i]=a[i]-b[i];    //for (int i=0;i<p;i++) cout<<a[i]<<" "; cout<<endl;//  for (int i=0;i<p;i++) cout<<b[i]<<" "; cout<<endl;}void clear(data &e){    for (int i=0;i<p;i++)     for (int j=0;j<p;j++) e.a[i][j]=0;}data mul(data a,data b){    data c;    for (int i=0;i<p;i++)     for (int j=0;j<p;j++) {        c.a[i][j]=0;        for (int k=0;k<p;k++)          c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;     }    return c;}data quickpow(data num,int x){    data base=num; data ans=c;    while (x) {        if (x&1) ans=mul(ans,base);        x>>=1;        base=mul(base,base);    }    return ans;}LL solve(int a[]){    clear(e);    for (int i=0;i<p;i++)     for (int j=0;j<p;j++)      e.a[i][(i+j)%p]+=a[j],e.a[i][(i+j)%p]%=mod;    data ans=quickpow(e,n);    return ans.a[0][0];}int main(){    freopen("count.in","r",stdin);    freopen("count.out","w",stdout);    scanf("%d%d%d",&n,&m,&p);    init();     for (int i=0;i<p;i++) c.a[i][i]=1;    LL t=solve(a)-solve(b);    printf("%I64d\n",(t%mod+mod)%mod);}



Day 2

T1

这里写图片描述
这里写图片描述

题解

01分数规划+费用流。
看到C=a1+a2+...+anb1+b2+...+bn就应该想到01分数规划。
先考虑如果每两个人之间只有一个有关的权值该怎么做?那么问题就变成了最大权匹配。这个貌似有一个叫做KM的算法可以快速求解,但是费用流也很好用啊。
S>i 容量为1,费用为0
j>T 容量为1,费用为0
i>j 容量为1,费用为val[i][j]
二分答案,然后将边权赋值成a[i][j]midb[i][j],跑最大费用最大流,如果最后的费用为正,说明答案还可以更大。
据学长说,把double运算变成整数运算会快哦。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#include<cmath>#define N 50003#define inf 1000000000#define eps 1e-9using namespace std;int n,m,tot,point[N],nxt[N],v[N],remain[N],last[N],can[N],S,T;double a[203][230],b[203][203],len[N],dis[N],ans;int head,tail,q[N*10];void add(int x,int y,int z,double k){    tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; len[tot]=k;    tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; len[tot]=-k;}int addflow(int s,int t){    int now=t; int ans=inf;    while (now!=s) {        ans=min(ans,remain[last[now]]);        now=v[last[now]^1];    }    now=t;    while (now!=s) {        remain[last[now]]-=ans;        remain[last[now]^1]+=ans;        now=v[last[now]^1];    }    return ans;}bool spfa(int s,int t){    for (int i=1;i<=t;i++) dis[i]=-inf,can[i]=0;    can[s]=1; dis[s]=0;    head=0; tail=0; q[++tail]=s;    while (head<tail) {        int now=q[++head];        for (int i=point[now];i!=-1;i=nxt[i])         if (dis[v[i]]<dis[now]+len[i]&&remain[i]) {            dis[v[i]]=dis[now]+len[i];            last[v[i]]=i;            if (!can[v[i]]) {                can[v[i]]=1;                q[++tail]=v[i];            }         }        can[now]=0;    }    if (dis[t]==-inf) return false;    int flow=addflow(s,t);    ans+=dis[t]*flow;    return true;}void solve(int s,int t){    while (spfa(s,t));}bool check(double mid){    tot=-1;     memset(point,-1,sizeof(point));    S=1; T=2*n+2;    for (int i=1;i<=n;i++)  add(S,i+1,1,0);    for (int i=1;i<=n;i++) add(i+n+1,T,1,0);    for (int i=1;i<=n;i++)     for (int j=1;j<=n;j++) add(i+1,j+n+1,1,a[i][j]-mid*b[i][j]);    //cout<<tot<<endl;    ans=0; solve(S,T);    return ans>=-eps;}int main(){    freopen("ball.in","r",stdin);    freopen("ball.out","w",stdout);    scanf("%d",&n); double sum=0;    for (int i=1;i<=n;i++)     for (int j=1;j<=n;j++) scanf("%lf",&a[i][j]),sum=max(sum,a[i][j]);    for (int i=1;i<=n;i++)     for (int j=1;j<=n;j++) scanf("%lf",&b[i][j]);    double l=0; double r=sum; double ans=0;    while (r-l>=eps) {        double mid=(l+r)/2;        if (check(mid)) ans=max(ans,mid),l=mid+eps;        else r=mid-eps;    }    printf("%.6lf\n",ans);}



T2

这里写图片描述

题解

KMP+高斯消元
设N为未结束状态的概率。
假设用两个串TTH和HTT,设第一个获胜的概率是A,第二个人获胜的概率为B
如果在N后面加上TTH,那么有三种可能
NTTH=A+BTH+BH ,是什么意思呢?就是如果在N后面加入TTH,那么第一个人猜的序列出现在了硬币序列中,第一个人获胜,但是N是什么我们不清楚,但是有可能到达第一个T或者第二个T的时候第二个人就获胜了。
所以对于状态NTTH,可以由三个状态得到。
123N=A+12B+122B12表示的是正反面的概率。
这样我们得到了n个方程,但是有n+1个未知量,因为所有人获胜的总概率是1,那么我们加入这个方程就成功得到了n+1个未知量,n+1个方程。高斯消元直接解就可以了
那么我们怎么得到每个串之间类似A,B的关系呢?发现满足A的前缀是B的后缀,这不就是失配的定义么。所以直接将两个串连起来,用KMP求失配即可。系数就是12m,需要注意的是系数应该是末位失配一直沿着fail指针向前跳,经过的所有点的概率和。

代码

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#define N 1003using namespace std;double mi[N],a[N][N],b[N],ans[N];int n,m,t[N],len;char s[N][N],ch[N];void gauss(int n){    for (int i=1;i<=n;i++){        int num=i;        for (int j=i+1;j<=n;j++)         if (fabs(a[j][i])>fabs(a[num][i])) num=j;        if (num!=i) {            for (int j=1;j<=n;j++) swap(a[num][j],a[i][j]);            swap(b[num],b[i]);        }        for (int j=i+1;j<=n;j++)          if (a[j][i]) {            double t=a[j][i]/a[i][i];            for (int k=1;k<=n;k++)             a[j][k]-=a[i][k]*t;            b[j]-=b[i]*t;         }    }    for (int i=n;i>=1;i--){        ans[i]=b[i];        for (int j=i+1;j<=n;j++)         if (a[i][j]) ans[i]-=ans[j]*a[i][j];        ans[i]/=a[i][i];    }}void calc(){    t[1]=0;    for (int i=1;i<=len;i++) {        int j=t[i];        while (ch[j]!=ch[i]&&j) j=t[j];        t[i+1]=j+1;    }}int main(){    freopen("game.in","r",stdin);    freopen("game.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) scanf("%s",s[i]+1);    mi[0]=1.0;    for (int i=1;i<=m;i++) mi[i]=mi[i-1]*0.5;     for (int i=1;i<=n;i++)     for (int j=1;j<=n;j++) {        len=0;        for (int k=1;k<=m;k++) ch[++len]=s[i][k];        for (int k=1;k<=m;k++) ch[++len]=s[j][k];        calc();         int k=t[len+1];        while (k>1) {            a[i][j]+=mi[m-k+1];            k=t[k];         }     }    double p=1.0/(double)(1<<m);    for (int i=1;i<=n;i++) a[i][n+1]=-p;    for (int i=1;i<=n;i++) a[n+1][i]=1.0;    b[n+1]=1;    gauss(n+1);    for (int i=1;i<=n;i++) printf("%.7lf\n",ans[i]);}



T3

这里写图片描述
这里写图片描述

题解

线段树
首先对a的求解式子进行变形

a=Ri=L(xix¯)(yiy¯)Ri=L(xix¯)2

a=Ri=Lxiyix¯yiy¯xi+x¯y¯Ri=Lxi2+x¯22x¯xi

其实上面式子的计算就变成了好几部分,我们可以用线段树分开维护一下。
sumx 区间[l,r]中所有xi的和
sumy 区间[l,r]中所有yi的和
xy 区间[l,r]中所有xi*yi的和
sq 区间中所有xi^2的和
squ Ri=Li2
sum Ri=Li
tagx 针对x的区间增加标记
tagy 针对y的区间增加标记
cx 针对x的区间覆盖标记
cy 针对y的区间覆盖标记
上面式子中的x¯,y¯都可以通过区间查询后计算。x¯=sumx(RL+1),y¯=sumy(RL+1)
len=RL+1,那么
a=xyx¯sumyy¯sumx+lenx¯y¯sq+lenx¯2x¯sumx

说几个主要的维护过程吧
(1)(x+s)(y+t)=xy+sy+tx+st
对应到线段树中的修改 xy=xy+sumxt+sumys+lenst
(2) x>s+i,y>t+i
对应到线段树中的修改 sumx=lens+sum,sumy=lent+sum
sq=sslen+squ+2ssum
xy=stlen+squ+(s+t)sum
(3)增加标记与覆盖标记的冲突
如果是覆盖标记遇到加法标记,覆盖标记正常打,增加标记清零
如果是增加标记遇到覆盖标记,就将增量直接加给覆盖标记

写的过程中有一个小细节需要注意,就i*i可能会炸int,注意加强转啊!!!

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 200003#define eps 1e-9#define inf 1000000000using namespace std;struct data {    double sumx,sumy,xy,sq,sum,squ;    double tagx,tagy,cx,cy;}tr[N*4];double xi[N],yi[N];int n,m;data update(data l,data r){    data now; now.tagx=now.tagy=0;    now.cx=now.cy=inf;    now.sumx=l.sumx+r.sumx;    now.sumy=l.sumy+r.sumy;    now.xy=l.xy+r.xy;    now.sq=l.sq+r.sq;    now.squ=l.squ+r.squ;     now.sum=l.sum+r.sum;    return now;}void build(int now,int l,int r){    if(l==r) {        tr[now].sumx=xi[l]; tr[now].sumy=yi[l];         tr[now].xy=xi[l]*yi[l]; tr[now].sq=xi[l]*xi[l];        tr[now].sum=l; tr[now].squ=(double)l*(double)l;        return;    }    int mid=(l+r)/2;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    tr[now]=update(tr[now<<1],tr[now<<1|1]);}void calc(int now,int l,int r,double valx,double valy){    double len=(r-l+1);    tr[now].tagx+=valx; tr[now].tagy+=valy;    tr[now].sq+=len*valx*valx+2.0*valx*tr[now].sumx;    tr[now].xy+=valx*tr[now].sumy+valy*tr[now].sumx+valx*valy*len;    tr[now].sumx+=valx*len; tr[now].sumy+=valy*len;    if (tr[now].cx==inf&&tr[now].cy==inf) return;    tr[now].cx+=valx; tr[now].cy+=valy;    tr[now].tagx=tr[now].tagy=0;}void cover(int now,int l,int r,double valx,double valy){    double len=(r-l+1);    tr[now].cx=valx; tr[now].cy=valy; tr[now].tagx=tr[now].tagy=0;    tr[now].sq=tr[now].squ+tr[now].sum*2.0*valx+valx*valx*len;    tr[now].xy=tr[now].squ+(valx+valy)*tr[now].sum+valx*valy*len;    tr[now].sumx=tr[now].sum+len*valx;    tr[now].sumy=tr[now].sum+len*valy;}void pushdown(int now,int l,int r){    int mid=(l+r)/2;    if (tr[now].cx!=inf||tr[now].cy!=inf){        cover(now<<1,l,mid,tr[now].cx,tr[now].cy);        cover(now<<1|1,mid+1,r,tr[now].cx,tr[now].cy);        tr[now].cx=tr[now].cy=inf;    }    if (fabs(tr[now].tagx)>=eps||fabs(tr[now].tagy)>=eps) {        calc(now<<1,l,mid,tr[now].tagx,tr[now].tagy);        calc(now<<1|1,mid+1,r,tr[now].tagx,tr[now].tagy);        tr[now].tagx=0; tr[now].tagy=0;    }}data query(int now,int l,int r,int ll,int rr){    if (ll<=l&&r<=rr) return tr[now];    int mid=(l+r)/2;    pushdown(now,l,r); data ans; bool pd=false;    if (ll<=mid) ans=query(now<<1,l,mid,ll,rr),pd=true;    if (rr>mid) {        if (pd) ans=update(ans,query(now<<1|1,mid+1,r,ll,rr));        else ans=query(now<<1|1,mid+1,r,ll,rr);    }    return ans;}void qjchange(int now,int l,int r,int ll,int rr,double valx,double valy){    if (ll<=l&&r<=rr) {        calc(now,l,r,valx,valy);        return;    }    int mid=(l+r)/2;    pushdown(now,l,r);    if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,valx,valy);    if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,valx,valy);    tr[now]=update(tr[now<<1],tr[now<<1|1]);}void qjcover(int now,int l,int r,int ll,int rr,double valx,double valy){    if (ll<=l&&r<=rr) {        cover(now,l,r,valx,valy);        return;    }    int mid=(l+r)/2;    pushdown(now,l,r);    if (ll<=mid) qjcover(now<<1,l,mid,ll,rr,valx,valy);    if (rr>mid) qjcover(now<<1|1,mid+1,r,ll,rr,valx,valy);    tr[now]=update(tr[now<<1],tr[now<<1|1]);}int main(){    freopen("relative.in","r",stdin);    freopen("relative.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) scanf("%lf",&xi[i]);    for (int i=1;i<=n;i++) scanf("%lf",&yi[i]);    build(1,1,n);    for (int i=1;i<=m;i++) {        int opt,l,r; scanf("%d",&opt);        if (opt==1) {            scanf("%d%d",&l,&r);            data a=query(1,1,n,l,r); double len=r-l+1;            double ans=0,ans1=0; double bx=a.sumx/len; double by=a.sumy/len;            ans=a.xy-bx*a.sumy-by*a.sumx+bx*by*len;            ans1=len*bx*bx+a.sq-2.0*bx*a.sumx;            printf("%.10lf\n",ans/ans1);        }        if (opt==2){            double s,t;            scanf("%d%d%lf%lf",&l,&r,&s,&t);            qjchange(1,1,n,l,r,s,t);        }        if (opt==3) {            double s,t; scanf("%d%d%lf%lf",&l,&r,&s,&t);            qjcover(1,1,n,l,r,s,t);        }    }}
1 0
原创粉丝点击