Wannafly挑战赛13

A题模拟

B题等价于有n^2 -1个白球 1个黑球 摸出来m个摸到黑球的概率 组合数学搞搞

C题我猜了下,就是1到n行 每行加0,1,2,...n-1 每列加1,n+1,2n+1.....n^2-n+1是一种可行解 然后两边全排列的情况也行,然后交换行列的位置也行,所以是2*(p!)^2

D题切一个蛋糕肯定是均匀切划算,因为不均匀切这一刀就会贡献质量差,然后就是找到最大的蛋糕,对它多切一刀看行不行模拟。

E题先把线段按右端点排序,能与当前线段产生异或最大的会排在前面,我们就从左到右处理,首先对于当前处理的线段l,r先二分出之前线段的r在当前线段的[l,r]之间的范围,然后就是查询这个范围的线段的l+r,与l-r ,画一画就知道了。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int maxn = 2e5+9;
struct line{
    int l,r;
    bool operator <(line a)const{
        return r<a.r;
    }
}l[maxn];
const int inf = 0x3f3f3f3f;
struct Node{
    int p[2];
}node[maxn<<2];
void build(int l,int r,int root){
    if(l==r){
        node[root].p[0] = inf;
        node[root].p[1] = -inf;
        return ;
    }
    int mid=l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
}
void pushup(int root){
    node[root].p[0] =min(node[root<<1].p[0],node[root<<1|1].p[0]);
    node[root].p[1] =max(node[root<<1].p[1],node[root<<1|1].p[1]);
}
void update(int l,int r,int root,int pos,int p0,int p1){
    if(l==r){
        node[root].p[0] = p0;
        node[root].p[1] = p1;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) update(l, mid, root<<1, pos, p0, p1);
    else update(mid+1, r, root<<1|1, pos, p0, p1);
    pushup(root);
}
int ql,qr;
int pp0,pp1;
void query(int l,int r,int root){
    if(ql<=l && r<=qr) {
        pp0 = min(pp0,node[root].p[0]);
        pp1 = max(pp1,node[root].p[1]);
        return ;
    }
    int mid=l+r>>1;
    if(qr<=mid) {
        query(l, mid, root<<1);
    }else if(ql>mid) {
        query(mid+1, r,root<<1|1);
    }else {
        query(l, mid, root<<1);
        query(mid+1, r, root<<1|1);
    }
}
int bs(int ll,int rr,int val){
    int ans = rr;
    while (ll<=rr) {
        int mid=ll+rr>>1;
        if(l[mid].r>=val){
            rr=mid-1;
            ans = mid;
        }else{
            ll = mid+1;
        }
    }
    return ans;
}
int main(int argc, const char * argv[]) {
    int n;
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&l[i].l,&l[i].r);
    }
    sort(l+1,l+1+n);
    build(1,n,1);
    int anss  = 0;
    for(int i=1;i<=n;i++){
        update(1, n, 1, i, l[i].l+l[i].r,l[i].l-l[i].r);
        qr = i;
        ql = bs(1,i,l[i].l);
        pp0 = inf;
        pp1 = -inf;
        query(1, n, 1);
        anss = max(anss,l[i].l+l[i].r-pp0);
        anss = max(anss,l[i].r-l[i].l+pp1);
    }
    printf("%d\n",anss);
    return 0;
}

  F题,主要思路就是通过对可爱值的分块,优化q^2的大暴力,首先我们可以在n+q的时间内处理Q个修改对n个点的影响,然后我们也有O(1)的算法解决已知u,v路径上被放了花,然后任意一点到这路径花的距离和,然后我门就可以把询问分块,分成q/N块,对于新来的询问,我们放进去询问中,如果询问是N的倍数,我们就重构之前所有的询问,每块重新维护的复杂度是n 然后一共有q/N块,重构的次数不会超过q/N次,反正就十分血腥暴力。

主要学到了把dfs改成了非递归的形式,还有树上差分的玩法(该点的真实值等于其所有子节点的差分数组和),好好写了一遍RMQ-LCA,log2打表的正确姿势,还有auto关键字玩lambda表达式,inplace_merge原地归并(暴力重构),还有lower_bound和upper_bound的手动实现和std玩法(感受到了前开后闭区间的优越性)。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
typedef long long int ll;
/*
1.实现RMQ-LCA
*/
const int maxn = 1e5+9;
const int S = 800;
const int N = maxn/S+5;
const int K = 18;
ll VAL[N][maxn];
struct query{
    int u,v,x;
}Q[maxn];
vector<int> vv[maxn];
int dep[maxn];
int ST_table[18][maxn<<1],first[maxn],dfsv[maxn],father[maxn];
int stcnt,dfscnt;
int Log2[maxn<<1];
ll qz[maxn];
void dfs(int now,int fa){
    ST_table[0][++stcnt] = now;
    first[now] = stcnt;
    dfsv[++dfscnt] = now;
    for(auto v:vv[now]) if(fa != v){
        dep[v] = dep[now]+1;
        father[v] = now;
        dfs(v, now);
        ST_table[0][++stcnt] = now;
    }
}
inline int depmin(int u,int v){
    return dep[u]<dep[v]?u:v;
}
void ST_init(){

    for(int i=1;i<18;i++){
        for(int j=1;j+(1<<(i-1))<=stcnt;j++){
            ST_table[i][j] = depmin(ST_table[i-1][j],ST_table[i-1][j+(1<<(i-1))]);
        }
    }
}

inline int lca(int u,int v){
    int posu = first[u];
    int posv = first[v];
    if(posu>posv) swap(posu,posv);
    int step = Log2[posv-posu+1];
    return depmin(ST_table[step][posu],ST_table[step][posv-(1<<step)+1]);
}
inline ll cal(ll a,ll b){
    if(a==0) a++;
    return qz[b]-qz[a-1];
}
inline ll cal(int u,int v,int x){
    int lcauv =lca(u,v);
    int lcauvx = lca(lcauv,x);
    if(dep[lcauvx]<dep[lcauv]){
        ll dis1 = dep[x]+dep[lcauv]-2*dep[lcauvx];
        ll dis2 = dep[x]+dep[u]-2*dep[lcauvx];
        ll dis3 = dep[x]+dep[v]-2*dep[lcauvx];
        return cal(dis1,dis2)+cal(dis1, dis3)-dis1;
    }
    int lcaux = lca(u,x);
    if(dep[lcaux]<=dep[lcauv]){
        swap(u,v);
        lcaux = lca(u,x);
    }
    ll dis1 = dep[x]-dep[lcaux];
    ll dis2 = dep[x]+dep[u]-2*dep[lcaux];
    ll dis3 = dep[x]+dep[v]-2*dep[lcauv];
    return cal(dis1,dis2)+cal(dis1, dis3)-dis1;
}
int P[maxn];
ll dp[maxn];
void build(query *Q,ll *val,int n){
    for(int i=0;i<=n;i++){
        val[i] = 0;
        P[i] = 0;
        dp[i] = 0;
    }
    for(int i=0;i<S;i++){
        int u = Q[i].u,v = Q[i].v,lcauv=lca(u,v);
        P[u]++,P[v]++,P[lcauv]--,P[father[lcauv]]--;
    }
    for(int i=n;i>=1;i--){
        int u = dfsv[i];
        int v = father[u];
        P[v]+=P[u];
        dp[u]+=P[u];
        dp[v]+=dp[u];
        val[v]+=val[u]+dp[u];
    }
    for(int i=1;i<=n;i++){
        int u= dfsv[i];
        val[u] = val[father[u]]+dp[1]-(dp[u]<<1);
    }
    
}
int allquery;
int bigall;
inline int lower(int st,int ed,int x){
    int ret = ed;
    while (st<ed) {
        int mid= st+ed>>1;
        if(Q[mid].x>=x){
            ret = mid;
            ed = mid;
        }else{
            st = mid+1;
        }
    }
    return ret;
}
inline int upper(int st,int ed,int x){
    int ret = ed;
    while (st<ed) {
        int mid= st+ed>>1;
        if(Q[mid].x>x){
            ret = mid;
            ed = mid;
        }else{
             st = mid+1;
        }
    }
    return ret;
}
int main(int argc, const char * argv[]) {
    for(int i=2;i<(maxn<<1);i++){
        Log2[i] = Log2[i>>1]+1;
    }
    for(int i=0;i<maxn;i++){
        qz[i] = 1ll*(i+1)*i/2;
    }
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        vv[u].push_back(v);
        vv[v].push_back(u);
    }
    dep[1] = 0;
    dfs(1,0);
    ST_init();
    while (m--) {
        int ty,x,y,z;
        scanf("%d%d%d%d",&ty,&x,&y,&z);
        if(ty==1){
            Q[allquery++] ={x,y,z};
            if(allquery%S==0){
                auto cmp = [](const query&A,const query&B){return A.x<B.x;};
                sort(Q+bigall, Q+allquery, cmp);
                inplace_merge(Q, Q+bigall, Q+allquery, cmp);
                for(int i=0;i<(bigall=allquery)/S;i++){
                    build(Q+i*S, VAL[i], n);
                }
            }
        }else{
            ll res= 0;
            for(int i=bigall;i<allquery;i++) if(Q[i].x<=y && Q[i].x>=x){
                res+= cal(Q[i].u, Q[i].v, z);
            }
            int L = lower(0, bigall, x);
            //int L=lower_bound(Q,Q+bigall,x,[](query A,int x){return A.x<x;})-Q;
            //int R=upper_bound(Q,Q+bigall,y,[](int x,query A){return x<A.x;})-Q;
            int R = upper(0, bigall, y);
            if(L/S==R/S) {
                for(int i=L;i<R;i++){
                    res+= cal(Q[i].u, Q[i].v, z);
                }
            }
            else{
                for(int i=L/S+1;i<R/S;i++) res+=VAL[i][z];
                for(int i=L;i<L/S*S+S;i++) res+=cal(Q[i].u,Q[i].v,z);
                for(int i=R/S*S;i<R;i++) res+=cal(Q[i].u,Q[i].v,z);
            }
            printf("%lld\n",res);
        }
    }
    return 0;
}
/*
 10 20
 6 7
 1 2
 5 4
 1 3
 10 8
 7 9
 1 8
 1 4
 2 6
 1 5 1 27280262
 1 2 4 27245688
 2 27234840 27290934 6
 1 10 6 27227228
 2 27313334 27321446 3
 1 9 10 27258713
 1 3 4 27249714
 2 27270810 27309316 1
 1 9 2 27254034
 2 27292791 27302394 10
 1 7 5 27319311
 1 5 6 27301947
 1 10 1 27318014
 2 27247634 27320484 9
 1 10 5 27299018
 2 27240281 27286743 8
 2 27296751 27319246 4
 2 27309633 27314750 9
 2 27257490 27301409 6
 2 27235007 27294034 2
 
 */

  

posted @ 2018-04-09 12:04  tjucxz  阅读(115)  评论(0编辑  收藏  举报