当前位置: 代码迷 >> 综合 >> 2021牛客暑期多校训练营#2:L-WeChat Walk
  详细解决方案

2021牛客暑期多校训练营#2:L-WeChat Walk

热度:52   发布时间:2023-12-04 09:06:55.0

L-WeChat Walk

原题链接:https://ac.nowcoder.com/acm/contest/11253/L

文章目录

  • L-WeChat Walk
    • 题目大意
    • 解题思路
      • 1
      • 2
        • 代码
      • 3
        • 代码
      • 4
    • 代码实现
    • ps:

题目大意

n ( 1 ≤ n ≤ 2 ? 1 0 5 ) n(1\le n\le 2·10^5) n(1n2?105)个人,他们的好友关系可以用有 n n n个点, m ( 1 ≤ m ≤ 2 ? 1 0 5 ) m(1\le m\le 2·10^5) m(1m2?105)的图来表示。

每个人会给出ta的微信步数,如果一个人的微信步数大于零,且严格大于他好友列表中任何一个人的步数,则称ta为“步数冠军”。

一天被分成 q q q个时刻,求每个人是“步数冠军”的时间总合。每一时刻,编号为 u u u的人,新走了 m m m步。

任何人的总步数均不超过 1 0 4 10^4 104

解题思路

1

我们先考虑能否直接枚举每个点:

此图为完全图时:在这里插入图片描述
在草稿纸上一算, O ( m q ) O(mq) O(mq)!tle是少不了了。

此图为菊花图时:
在这里插入图片描述
拿出万能的草稿纸,一算,可不得了, O ( m 2 q ) O(m^2q) O(m2q),憋想了。

不对,加几个特判也还是一条好汉!那这可怎么办?:
在这里插入图片描述
所以说,不要妄想全部暴力了。

2

对于朋友比较少的人比如我,祭出我们的二分打法,来试试看吧!

将枚举的人用函数表示,如下图:
在这里插入图片描述

ta的朋友与ta的关系如下:
在这里插入图片描述

“步数冠军”是蓝线:

在这里插入图片描述

那么,求每个人获得的蓝线总量即可。

代码

for(int j=0;j<tm[i].size();j ++){
    int y=tm[i][j].second;int x=tm[i][j].first;int r=q;if(j<tm[i].size()-1)r=tm[i][j+1].second;for(auto v:e[i]){
    auto it=lower_bound(tm[v].begin(),tm[v].end(),(pair<int,int>){
    x,0});if(it!=tm[v].end())r=min(r,(*it).second);}ans+=max(0,r-y) ;} 

3

当一个人朋友很多时,显然不能直接枚举。

ta和ta的朋友表示如下:
在这里插入图片描述

“步数冠军”还是用蓝线表示:

在这里插入图片描述

每一时刻都对应一个步数,对应那一刻的“步数冠军”,把所有作为步数冠军的时间加起来,就得到了答案。

代码

vector<int>res(10010,q+10);for(auto v:e[i])for(auto x:tm[v])res[x.first]=min(res[x.first],x.second);for(int i=9999;i>=1;i--)res[i]=min(res[i],res[i+1]);for(int j=0;j<tm[i].size();j++){
    int y=tm[i][j].second;int x=tm[i][j].first;int r=q;if(j<tm[i].size()-1)r=tm[i][j+1].second;r=min(r,res[x]) ;ans+=max(0,r-y) ;}

4

由分块思想得出大小点判断应以 n \sqrt{n} n ?为分界点此题完结

代码实现

ac代码如下

#include<bits/stdc++.h>
using namespace std;
const int s=447;
int n,m,q;
int main()
{
    cin>>n>>m>>q;vector < vector< pair<int,int> > >tm(n+100); vector<vector<int> > e(n+100);for(int i=0;i<m;i++){
    int x,y,u;cin>>x>>y;e[x].push_back(y),e[y].push_back(x);}for(int i=1;i<=q;i++){
    int u,w;cin>>u>>w;tm[u].push_back({
    w,i});}for(int i=1;i<=n;i++)for(int j=1;j<tm[i].size();j++)tm[i][j].first+=tm[i][j-1].first;for(int i=1;i<=n;i++){
    int ans=0; if(e[i].size()<=s){
    for(int j=0;j<tm[i].size();j ++){
    int y=tm[i][j].second;int x=tm[i][j].first;int r=q;if(j<tm[i].size()-1)r=tm[i][j+1].second;for(auto v:e[i]){
    auto it=lower_bound(tm[v].begin(),tm[v].end(),(pair<int,int>){
    x,0});if(it!=tm[v].end())r=min(r,(*it).second);}ans+=max(0,r-y) ;} }else{
    vector<int>res(10010,q+10);for(auto v:e[i])for(auto x:tm[v])res[x.first]=min(res[x.first],x.second);for(int i=9999;i>=1;i--)res[i]=min(res[i],res[i+1]);for(int j=0;j<tm[i].size();j++){
    int y=tm[i][j].second;int x=tm[i][j].first;int r=q;if(j<tm[i].size()-1)r=tm[i][j+1].second;r=min(r,res[x]) ;ans+=max(0,r-y) ;}}cout<<ans;puts("");}}	

ps:

这是我的第八篇博客,也是我最长最详细的一篇。