• 18/9/21模拟赛-Updated


            18/9/21模拟赛

    期望得分:100;实际得分:0  qwq

    拿到题目第一眼,我去,这不是洛谷原题(仓鼠找Sugar)吗

    又多看了几眼,嗯,对,除了是有多组数据外,就是原题

    然后码码码。。。。自以为写的很对 qwq

    评测结束后。。。为什么我T1没有输出啊啊啊。。。

    经某童鞋帮忙,发现

    第一次被文件输入输出坑 qwqwq。。。

    加上后就A了,白丢100 pts 蓝瘦

    思路:树剖分别求LCA,然后判断LCA是否在另一条路径上

    不要忘记清空数组!

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int M = 100005;
    int T, n, m, tot;
    int to[M << 1], net[M << 1], head[M];
    int deep[M], top[M], dad[M], size[M];
    
    void add(int u, int v) {
        to[++tot] = v; net[tot] = head[u]; head[u] = tot;
        to[++tot] = u; net[tot] = head[v]; head[v] = tot;
    }
    
    void dfs(int now) {
        size[now] = 1;
        deep[now] = deep[dad[now]] + 1;
        for (int i = head[now]; i; i = net[i])
            if (to[i] != dad[now]) {
                dad[to[i]] = now;
                dfs(to[i]);
                size[now] += size[to[i]];
            }
    }
    
    void dfsl(int now) {
        int t = 0;
        if (!top[now]) top[now] = now;
        for (int i = head[now]; i; i = net[i])
            if (to[i] != dad[now] && size[to[i]] > size[t])
                t = to[i];
        if (t) {
            top[t] = top[now];
            dfsl(t);
        }
        for (int i = head[now]; i; i = net[i])
            if (to[i] != dad[now] && to[i] != t)
                dfsl(to[i]);
    }
    
    int lca(int x, int y) {
        while (top[x] != top[y]) {
            if (deep[top[x]] < deep[top[y]])
                swap(x, y);
            x = dad[top[x]];
        }
        return deep[x] > deep[y] ? y : x;
    }
    
    void clear() {
        tot = 0;
        memset(to, 0, sizeof to);
        memset(net, 0, sizeof net);
        memset(dad, 0, sizeof dad);
        memset(top, 0, sizeof top);
        memset(head, 0, sizeof head);
        memset(deep, 0, sizeof deep);
        memset(size, 0, sizeof size);
    }
    
    int main() {
        freopen("railway.in","r",stdin);
        freopen("railway.out","w",stdout);
        scanf("%d", &T);
        for (int q = 1; q <= T; ++q) {
            if (q != 1) clear();
            scanf("%d%d", &n, &m);
            for (int i = 1; i < n; ++i) {
                int u, v;
                scanf("%d%d", &u, &v);
                add(u, v);
            }
            dfs(1);
            dfsl(1);
            for (int i = 1; i <= m; ++i) {
                int a, b, c, d;
                scanf("%d%d%d%d", &a, &b, &c, &d);
                int S = lca(a, b);
                int R = lca(c, d);
                if (S < R) {
                    swap(S, R);
                    swap(a, c);
                    swap(b, d);
                }
                if (lca(S, c) == S || lca(S, d) == S) printf("YES
    ");
                else printf("NO
    ");
            }
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
    View Code

     

    期望得分:100? 实际得分:20  (那80pts的都TLE了。。。)

    思路:线段树维护区间的最大最小值,然后枚举每一个区间求解

    事实证明,我真的不会算时间复杂度 qwq

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    
    #ifdef WIN32
    #define LL "%I64d
    "
    #else
    #define LL "%lld
    "
    #endif
    
    using namespace std;
    typedef long long Ll;
    const int M = 100005;
    int n, m;
    Ll ans;
    int ll[M << 2], rr[M << 2];
    int maxn[M << 2], minn[M << 2];
    
    void update(int now) {
        maxn[now] = max(maxn[now << 1], maxn[now << 1 | 1]);
        minn[now] = min(minn[now << 1], minn[now << 1 | 1]);
    }
    
    void build(int now, int l, int r) {
        ll[now] = l; rr[now] = r;
        if (l == r) {
            scanf("%d", &maxn[now]);
            minn[now] = maxn[now];
            return ;
        }
        int mid = (l + r) >> 1;
        build(now << 1, l, mid);
        build(now << 1 | 1, mid + 1, r);
        update(now);
    }
    
    int query(int now, int l, int r) {
        if (ll[now] == l && rr[now] == r)
            return maxn[now];
        int mid = (ll[now] + rr[now]) >> 1;
        if (l <= mid && mid < r) return max(query(now << 1, l, mid), query(now << 1 | 1, mid + 1, r));
        else if (r <= mid) return query(now << 1, l, r);
        else return query(now << 1 | 1, l, r);
    }
    
    int found(int now, int l, int r) {
        if (ll[now] == l && rr[now] == r)
            return minn[now];
        int mid = (ll[now] + rr[now]) >> 1;
        if (l <= mid && mid < r) return min(found(now << 1, l, mid), found(now << 1 | 1, mid + 1, r));
        else if (r <= mid) return found(now << 1, l, r);
        else return found(now << 1 | 1, l, r);
    }
    
    void clear() {
        ans = 0;
        memset(ll, 0, sizeof ll);
        memset(rr, 0, sizeof rr);
        memset(maxn, 0, sizeof maxn);
        memset(minn, 0, sizeof minn);
    }
    
    int main() {
        freopen("count.in","r",stdin);
        freopen("count.out","w",stdout);
        scanf("%d", &m);
        for (int q = 1; q <= m; ++q) {
            if (q != 1) clear();
            scanf("%d", &n);
            build(1, 1, n);
            for (int i = 1; i <= n; ++i)
                for (int j = i + 1; j <= n; ++j)
                    ans += (query(1, i, j) - found(1, i, j));
            printf(LL, ans);
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
    考场20pts代码

    正解:因为排列是随机的,所以从每个点向后可能的差值最多 2logn 个,所以答案最多只可能有nlogn 种,用单调队列找出来统计即可

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef pair<int,int> pr;
    const double pi=acos(-1);
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define Rep(i,u) for(int i=head[u];i;i=Next[i])
    #define clr(a) memset(a,0,sizeof a)
    #define pb push_back
    #define mp make_pair
    #define putk() putchar(' ')
    ld eps=1e-9;
    ll pp=1000000007;
    ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
    ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
    ll gcd(ll a,ll b){return (!b)?a:gcd(b,a%b);}
    ll read(){
        ll ans=0;
        char last=' ',ch=getchar();
        while(ch<'0' || ch>'9')last=ch,ch=getchar();
        while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
        if(last=='-')ans=-ans;
        return ans;
    }
    void put(ll a){
        if(a<0)putchar('-'),a=-a;
        int top=0,q[20];
        while(a)q[++top]=a%10,a/=10;
        top=max(top,1);
        while(top--)putchar('0'+q[top+1]);
    }
    //head
    #define N 210000
    int n,a[N],f1[N],f2[N],q[N];
    ll s[N];
    void solved(){
        n=read();
        rep(i,1,n)a[i]=read();
        a[n+1]=n+1;
        q[1]=n+1;
        int t=1;
        per(i,n,1){
            while(t && a[q[t]]<=a[i])--t;
            f1[i]=q[t];
            q[++t]=i;
        }
        a[n+1]=0;
        q[1]=n+1;
        t=1;
        per(i,n,1){
            while(t && a[q[t]]>=a[i])--t;
            f2[i]=q[t];
            q[++t]=i;
        }
        rep(i,0,n)s[i]=0;
        rep(i,1,n){
            int z1=i,z2=i;
            while(z1!=n+1  && z2!=n+1){
                if(f1[z1]<=f2[z2]){
                    int tt=max(z1,z2),zz=a[z1]-a[z2];
                    z1=f1[z1];
                    s[zz]+=max(z1,z2)-tt;
                }
                else{
                    int tt=max(z1,z2),zz=a[z1]-a[z2];
                    z2=f2[z2];
                    s[zz]+=max(z1,z2)-tt;
                }
            }
        }
        ll ans=0;
        rep(i,1,n-1)
            ans+=s[i]*i;
        cout<<ans<<endl;
    }
    int main(){
        freopen("count.in","r",stdin);
        freopen("count.out","w",stdout);
        int T=read();
        while(T--){
            solved();
        }
        return 0;
    }
    正解

     比题解更好的做法  ——By lgj

    分别求所有区间的最大值和、最小值和

    用单调栈维护,用sum记录已经求过的区间的最大值的和

    求最小值时,可将所有的数转为负数,重新跑一遍即可

    最后将两次求出的值相加即可

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<iostream>
    #define LL long long 
    using namespace std;
    const LL MAXN = 1e5 + 10;
    inline LL read() {
        char c = getchar(); LL x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    LL T, N;
    LL a[MAXN], q[MAXN];
    LL solve() {
        LL h = 1, t = 0, ans = 0, sum = 0;
        for(LL i = 1; i <= N; i++) {
            while(h <= t && a[i] > a[q[t]]) sum -= a[q[t]] * (q[t] - q[t - 1]), t--;
            q[++t] = i;
            ans += a[i] * (q[t] - q[t - 1]) + sum;
            sum += a[i] * (q[t] - q[t - 1]);
        }
        return ans;
    }
    int main() {
        freopen("count.in", "r", stdin);
        freopen("count.out", "w", stdout);
        T = read();
        while(T--) {
            N = read();
            for(LL i = 1; i <= N; i++) a[i] = read();
            LL ans = solve();
            for(LL i = 1; i <= N; i++) a[i] = -a[i];
            LL ans2 = solve();
            cout << ans + ans2 << endl;
        }
        return 0;
    }
    % lgj dalao

     

    期望得分:0;实际得分:0

    一开始以为样例错了,死活推不出来

    前一个小时做了前两题,剩下的时间大部分就在推样例发呆中度过了

    最后半小时才发现读错题 qwq

    然而暴力也写不完了。。。

    正解:对于每一条边统计有多少个区间跨过这条边即可

    统计这一问题的对偶问题,有多少个区间没跨过会更方便

     使用启发式合并+并查集统计子树内的,使用启发式合并+set 统计子树外的

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<set>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef pair<int,int> pr;
    const double pi=acos(-1);
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define Rep(i,u) for(int i=head[u];i;i=Next[i])
    #define clr(a) memset(a,0,sizeof a)
    #define pb push_back
    #define mp make_pair
    ld eps=1e-9;
    ll pp=1000000007;
    ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
    ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
    ll read(){
        ll ans=0;
        char last=' ',ch=getchar();
        while(ch<'0' || ch>'9')last=ch,ch=getchar();
        while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
        if(last=='-')ans=-ans;
        return ans;
    }
    //head
    #define N 110000
    int head[N],Next[N*2],v[N*2],num,fa[N],son[N],sum[N],n,s[N],Fa[N];
    ll ans=0,Sum,Sum2;
    bool vis[N];
    set<int>Q;
    set<int>::iterator it,it1,it2;
    int find(int x){
        if(x==Fa[x])return x;
        return Fa[x]=find(Fa[x]);
    }
    void add(int x,int y){
        v[++num]=y;Next[num]=head[x];head[x]=num;
    }
    void dfs1(int u){
        sum[u]=1;son[u]=0;
        for(int i=head[u];i;i=Next[i])
            if(v[i]!=fa[u]){
                fa[v[i]]=u;
                dfs1(v[i]);
                sum[u]+=sum[v[i]];
                if(!son[u] || sum[v[i]]>sum[son[u]])son[u]=v[i];
            }
    }
    ll cal(ll n){
        return n*(n-1)/2;
    }
    void Add(int u){
        Q.insert(u);
        it=Q.find(u);
        it1=it2=it;
        it1--;it2++;
        Sum2-=cal((*it2)-(*it1)-1);
        Sum2+=cal((*it)-(*it1)-1)+cal((*it2)-(*it)-1);
        vis[u]=1;
        if(vis[u-1]){
            int fx=find(u-1),fy=find(u);
            Sum+=(ll)s[fx]*s[fy];
            Fa[fx]=fy;
            s[fy]+=s[fx];
        }
        if(vis[u+1]){
            int fx=find(u+1),fy=find(u);
            Sum+=(ll)s[fx]*s[fy];
            Fa[fx]=fy;
            s[fy]+=s[fx];
        }
    }
    void bfs(int u){
        Add(u);
        for(int i=head[u];i;i=Next[i])
            if(v[i]!=fa[u])bfs(v[i]);
    }
    void clear(int u){
        s[u]=1;vis[u]=0;Fa[u]=u;
        for(int i=head[u];i;i=Next[i])
            if(v[i]!=fa[u])clear(v[i]);
    }
    void dfs2(int u){
        for(int i=head[u];i;i=Next[i])
            if(v[i]!=fa[u] && v[i]!=son[u]){
                dfs2(v[i]);
                clear(v[i]);
                Sum=0;
                Q.clear();
                Q.insert(0);
                Q.insert(n+1);
                Sum2=(ll)(n-1)*n/2;
            }
    
        if(son[u])dfs2(son[u]);
        for(int i=head[u];i;i=Next[i])
            if(v[i]!=fa[u] && v[i]!=son[u])bfs(v[i]);
    
        Add(u);
        
        ans+=(ll)n*(n-1)/2-Sum-Sum2;
    }
    int main(){
        freopen("treecnt.in","r",stdin);
        freopen("treecnt.out","w",stdout);
        n=read();
        Q.clear();
        Q.insert(0);
        Q.insert(n+1);
        Sum2=cal(n);
        rep(i,1,n)Fa[i]=i,s[i]=1,vis[i]=0;
        rep(i,2,n){
            int x=read(),y=read();
            add(x,y);
            add(y,x);
        }
        dfs1(1);
        dfs2(1);
        cout<<ans<<endl;
        return 0;
    }
    正解

      

  • 相关阅读:
    linux网络编程之socket编程(三)
    linux网络编程之socket编程(二)
    字符串转成时间戳
    xls的读写
    统计词语频率保存到xls
    信息时代的学习(对于人类)
    编码格式简介:ASCII码、ANSI、GBK、GB2312、GB18030和Unicode、UTF-8,BOM头
    ThinkPHP中:RBAC权限控制的实习步骤
    getField()和select()方法的区别
    按钮美化,变化显示效果
  • 原文地址:https://www.cnblogs.com/v-vip/p/9686528.html
Copyright © 2020-2023  润新知