acdream群赛(树状数组,Trie树)

太弱了。。。

J - Base Station

Time Limit: 20000/10000 MS (Java/Others)      Memory Limit: 512000/256000 KB (Java/Others)
Problem Description

 

移动通信系统中,通信网的建立主要通过基站来完成。

基站可以分为主基站和子基站。子基站和各个移动用户进行连接,子基站必须通过主基站来和外界实现通信。主基站可以覆盖到的范围是一个圆形区域,子基站和主基站的距离小于半径r才能被该主基站覆盖到。半径r由主基站的发射功率确定。

某个区域的移动通信网,包含2个主基站和N个子基站。它们的位置都可以对应到一个整数坐标上。如果子基站至少被一个主基站覆盖,则该子基站是激活的。

现在通信公司在调试设备,它们不停地改变主基站的发射功率,当两个主基站的覆盖半径分别为r1和r2时,需要知道有多少个子基站处于非激活状态。

 

 

 

Input

有若干组输入数据。

第一行是四个整数:x1、y1、x2、y2(1<=x1、y1、x2、y2<=10^9),表示两个主基站的坐标是(x1,y1)和(x2,y2)。

第二行是一个整数N(1<=N<=100000),表示有N个子基站。

接下来的N行,每行两个整数x、y(1<=x, y<=10^9),表示每个子基站的坐标。

接下来一行包含一个整数M(1<=M<=100000),表示有M个询问。

接下来的M行,每行两个整数r1、r2(1<=r1, r2<=10^9),表示询问当两个主基站的覆盖半径为r1和r2时,处于非激活状态的子基站数。
Output

对每个查询,输出答案。

Sample Input
1 10 5 2
5
2 6
1 9
3 8
6 7
4 12
5
1 1
3 2
8 2
2 2
3 2
Sample Output
5
3
0
4
3
简单数据结构。
到两个基站的距离,其实就构成了二维坐标。
其中一个按照顺序加入,另外一维用一维树状数组就可以查询了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
typedef long long LL;
struct node
{
    LL x,y;
}p[maxn];
struct circle
{
    LL r1,r2;
    int id;
}qu[maxn];
LL b[maxn];
int n,c[maxn],q,ans[maxn];
bool cmp1(node a,node b)
{
    return a.x>b.x;
}
bool cmp2(circle a,circle b)
{
    return a.r1>b.r1;
}
void add(int x,int v)
{
    while(x<=n)
    {
        c[x]+=v;
        x+=x&(-x);
    }
}
int sum(int x)
{
    int res=0;
    while(x>0)
    {
        res+=c[x];
        x-=x&(-x);
    }
    return res;
}
int main()
{
    freopen("in.txt","r",stdin);
    int x1,y1,x2,y2,x,y;
    while(scanf("%d%d%d%d",&x1,&y1,&x2,&y2)!=EOF)
    {
        scanf("%d",&n);
        int tot=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            p[i].x=(LL)(x-x1)*(x-x1)+(LL)(y-y1)*(y-y1);
            p[i].y=(LL)(x-x2)*(x-x2)+(LL)(y-y2)*(y-y2);
            b[++tot]=p[i].y;
        }
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            scanf("%lld%lld",&qu[i].r1,&qu[i].r2);
            qu[i].r1*=qu[i].r1;
            qu[i].r2*=qu[i].r2;
            qu[i].id=i;
        }
        sort(p,p+n,cmp1);//按到第一基站距离从大到小排序
        sort(b+1,b+tot+1);
        sort(qu,qu+q,cmp2);//按第一基站半径从大到小排序
        tot=unique(b+1,b+tot+1)-b-1;
        memset(c,0,sizeof(c));//因为前面的排序,所以。。。
        int cur=0;
        for(int i=0;i<q;i++)
        {
            while(cur<n&&p[cur].x>=qu[i].r1)//找出在第一个基站外面的
            {
                int pos=lower_bound(b+1,b+tot+1,p[cur].y)-b;//如果他也在第二个基站外面则这个位置加1
                add(pos,1);
                cur++;
            }
            int l=lower_bound(b+1,b+tot+1,qu[i].r2)-b;//找到第二个基站的范围,那么只要减去这个范围内的值就是答案
            ans[qu[i].id]=sum(n)-sum(l-1);
        }

        for(int i=0;i<q;i++)printf("%d\n",ans[i]);
    }
    return 0;
}

I - 喵喵的IDE

Time Limit: 20000/10000 MS (Java/Others)      Memory Limit: 512000/256000 KB (Java/Others)
Problem Description

喵喵有一个神奇的IDE,这个IDE自带一个cache,还有一个当前编辑区editarea,初始的时候这个 cache 中有一个字符串 cachebegin

喵喵想打按照顺序打N个字符串 x,她可以进行三种操作。

打之前 editarea 为空
1、从cache中拿出一个字符串 B直接赋值给editarea , editarea = B.(如果不拿那么不计入操作数)
2、如果editarea里面有字符,那wuyiqi可以删除掉editarea中最后一个字符。(删光了之后就不能删除啦!)
3、喵喵可以在editarea末尾插入一个任意字符。
如果editarea的字符串恰好与她要打的第i个字符串相同,那么她就完成了这次打印,并且这个字符串自动加入cache(cache中可能出现重复字符串),然后editarea自动清空。那么喵喵就会自动进入下一个字符串的打印阶段。
她想问,对于每次字符串输出,最少需要多少次操作。
1 ≤ N ≤ 105 , 字符串长度总和 ∑(Ai) <106 , cache_begin 长度< 100

Input

第一行一个整数T,代表数据组数。

对于每组数据第一行一个整数 N 代表要打印的字符串个数,还有一个字符串cachebegin

以下N 行每行一个字符串 Ai

A和 cachebegin 都只包含小写字母

Output
对于每组测试数据输出N个数。
Sample Input
1
3 a
a
ab
abc
Sample Output
1
2
2
Hint

一开始cache中为{"a"}
第一次操作直接拿出来{"a"}就好了

现在cache为{"a","a"}
拿出来"a",加入b,两次操作。

现在cache为{"a" , "a" , "ab"}
拿出来"ab",加入c。两次操作

先把 cache_begin 放到Trie 上面,并且在 Trie 树上记录每个节点距离当前子串叶子的距离。对于每个新串,在 Trie 上面求 Min{长度 – 已经走得距离 + 距离叶子距离} 。 计算结束之后把原串加入 Trie。
唯一 的 Trick 是有可能不从原来的Trie中拿,所以要把答案和本串长度取Min。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010*27;
const int sigma_size=30;
int ch[maxn][sigma_size],val[maxn];
int sz,N;
char s[110];
int idx(char x){return x-'a';}
void insert(char *ss,int len)
{
    int u=0;
    for(int i=0;i<len;i++)
    {
        int c=idx(ss[i]);
        if(!ch[u][c])
        {
            memset(ch[sz],0,sizeof(sz));

            val[sz]=len-i-1;
            ch[u][c]=sz++;
        }
        else val[sz]=min(val[sz],len-1-i);
        u=ch[u][c];
    }
}
int query(char *ss,int len)
{
    int u=0,sum=len;
    for(int i=0;i<len;i++)
    {
        int c=idx(ss[i]);
        if(!ch[u][c])break;
        else
        {
            sum=min(sum,val[ch[u][c]]+len-i);
            u=ch[u][c];
        }
    }
    return sum;
}
void solve()
{
    for(int i=0;i<N;i++)
    {
        scanf("%s",s);
        int len=strlen(s);
        int ans=query(s,len);
        printf("%d\n",ans);
        insert(s,len);
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        scanf("%s",s);
        int len=strlen(s);
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));
        insert(s,len);
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值